Example #1
0
bool NestLoopExecutor::p_init(AbstractPlanNode* abstract_node,
                              TempTableLimits* limits)
{
    VOLT_TRACE("init NestLoop Executor");

    NestLoopPlanNode* node = dynamic_cast<NestLoopPlanNode*>(abstract_node);
    assert(node);

    // Create output table based on output schema from the plan
    setTempOutputTable(limits);

    assert(m_tmpOutputTable);

    // NULL tuple for outer join
    if (node->getJoinType() == JOIN_TYPE_LEFT) {
        Table* inner_table = node->getInputTable(1);
        assert(inner_table);
        m_null_tuple.init(inner_table->schema());
    }

    // Inline aggregation can be serial, partial or hash
    m_aggExec = voltdb::getInlineAggregateExecutor(m_abstractNode);

    return true;
}
Example #2
0
bool NestLoopExecutor::p_init(AbstractPlanNode* abstract_node,
                              TempTableLimits* limits)
{
    VOLT_TRACE("init NestLoop Executor");

    NestLoopPlanNode* node = dynamic_cast<NestLoopPlanNode*>(abstract_node);
    assert(node);

    // Create output table based on output schema from the plan
    setTempOutputTable(limits);

    // NULL tuple for outer join
    if (node->getJoinType() == JOIN_TYPE_LEFT) {
        Table* inner_table = node->getInputTables()[1];
        assert(inner_table);
        m_null_tuple.init(inner_table->schema());
    }

    return true;
}
Example #3
0
bool NestLoopExecutor::p_execute(const NValueArray &params) {
    VOLT_DEBUG("executing NestLoop...");

    NestLoopPlanNode* node = dynamic_cast<NestLoopPlanNode*>(m_abstractNode);
    assert(node);
    assert(node->getInputTables().size() == 2);

    Table* output_table_ptr = node->getOutputTable();
    assert(output_table_ptr);

    // output table must be a temp table
    TempTable* output_table = dynamic_cast<TempTable*>(output_table_ptr);
    assert(output_table);

    Table* outer_table = node->getInputTables()[0];
    assert(outer_table);

    Table* inner_table = node->getInputTables()[1];
    assert(inner_table);

    VOLT_TRACE ("input table left:\n %s", outer_table->debug().c_str());
    VOLT_TRACE ("input table right:\n %s", inner_table->debug().c_str());

    //
    // Pre Join Expression
    //
    AbstractExpression *preJoinPredicate = node->getPreJoinPredicate();
    if (preJoinPredicate) {
        preJoinPredicate->substitute(params);
        VOLT_TRACE ("Pre Join predicate: %s", preJoinPredicate == NULL ?
                    "NULL" : preJoinPredicate->debug(true).c_str());
    }
    //
    // Join Expression
    //
    AbstractExpression *joinPredicate = node->getJoinPredicate();
    if (joinPredicate) {
        joinPredicate->substitute(params);
        VOLT_TRACE ("Join predicate: %s", joinPredicate == NULL ?
                    "NULL" : joinPredicate->debug(true).c_str());
    }
    //
    // Where Expression
    //
    AbstractExpression *wherePredicate = node->getWherePredicate();
    if (wherePredicate) {
        wherePredicate->substitute(params);
        VOLT_TRACE ("Where predicate: %s", wherePredicate == NULL ?
                    "NULL" : wherePredicate->debug(true).c_str());
    }

    // Join type
    JoinType join_type = node->getJoinType();
    assert(join_type == JOIN_TYPE_INNER || join_type == JOIN_TYPE_LEFT);

    int outer_cols = outer_table->columnCount();
    int inner_cols = inner_table->columnCount();
    TableTuple outer_tuple(node->getInputTables()[0]->schema());
    TableTuple inner_tuple(node->getInputTables()[1]->schema());
    TableTuple &joined = output_table->tempTuple();
    TableTuple null_tuple = m_null_tuple;

    TableIterator iterator0 = outer_table->iterator();
    while (iterator0.next(outer_tuple)) {

        // did this loop body find at least one match for this tuple?
        bool match = false;
        // For outer joins if outer tuple fails pre-join predicate
        // (join expression based on the outer table only)
        // it can't match any of inner tuples
        if (preJoinPredicate == NULL || preJoinPredicate->eval(&outer_tuple, NULL).isTrue()) {

            // populate output table's temp tuple with outer table's values
            // probably have to do this at least once - avoid doing it many
            // times per outer tuple
            joined.setNValues(0, outer_tuple, 0, outer_cols);

            TableIterator iterator1 = inner_table->iterator();
            while (iterator1.next(inner_tuple)) {
                // Apply join filter to produce matches for each outer that has them,
                // then pad unmatched outers, then filter them all
                if (joinPredicate == NULL || joinPredicate->eval(&outer_tuple, &inner_tuple).isTrue()) {
                    match = true;
                    // Filter the joined tuple
                    if (wherePredicate == NULL || wherePredicate->eval(&outer_tuple, &inner_tuple).isTrue()) {
                        // Matched! Complete the joined tuple with the inner column values.
                        joined.setNValues(outer_cols, inner_tuple, 0, inner_cols);
                        output_table->insertTupleNonVirtual(joined);
                    }
                }
            }
        }
        //
        // Left Outer Join
        //
        if (join_type == JOIN_TYPE_LEFT && !match) {
            // Still needs to pass the filter
            if (wherePredicate == NULL || wherePredicate->eval(&outer_tuple, &null_tuple).isTrue()) {
                joined.setNValues(outer_cols, null_tuple, 0, inner_cols);
                output_table->insertTupleNonVirtual(joined);
            }
        }
    }

    return (true);
}
Example #4
0
bool NestLoopExecutor::p_execute(const NValueArray &params, ReadWriteTracker *tracker) {
    VOLT_DEBUG("executing NestLoop...");

    NestLoopPlanNode* node = dynamic_cast<NestLoopPlanNode*>(abstract_node);
    assert(node);
    assert(node->getInputTables().size() == 2);

    Table* output_table_ptr = node->getOutputTable();
    assert(output_table_ptr);

    // output table must be a temp table
    TempTable* output_table = dynamic_cast<TempTable*>(output_table_ptr);
    assert(output_table);

    Table* outer_table = node->getInputTables()[0];
    assert(outer_table);

    Table* inner_table = node->getInputTables()[1];
    assert(inner_table);

    VOLT_TRACE ("input table left:\n %s", outer_table->debug().c_str());
    VOLT_TRACE ("input table right:\n %s", inner_table->debug().c_str());

    //
    // Join Expression
    //
    AbstractExpression *predicate = node->getPredicate();
    if (predicate) {
        predicate->substitute(params);
        VOLT_TRACE ("predicate: %s", predicate == NULL ?
                    "NULL" : predicate->debug(true).c_str());
    }

    int outer_cols = outer_table->columnCount();
    int inner_cols = inner_table->columnCount();
    TableTuple outer_tuple(node->getInputTables()[0]->schema());
    TableTuple inner_tuple(node->getInputTables()[1]->schema());
    TableTuple &joined = output_table->tempTuple();

    TableIterator iterator0(outer_table);
    while (iterator0.next(outer_tuple)) {

        // populate output table's temp tuple with outer table's values
        // probably have to do this at least once - avoid doing it many
        // times per outer tuple
        for (int col_ctr = 0; col_ctr < outer_cols; col_ctr++) {
            joined.setNValue(col_ctr, outer_tuple.getNValue(col_ctr));
        }

        TableIterator iterator1(inner_table);
        while (iterator1.next(inner_tuple)) {
            if (predicate == NULL || predicate->eval(&outer_tuple, &inner_tuple).isTrue()) {
                // Matched! Complete the joined tuple with the inner column values.
                for (int col_ctr = 0; col_ctr < inner_cols; col_ctr++) {
                    joined.setNValue(col_ctr + outer_cols, inner_tuple.getNValue(col_ctr));
                }
                output_table->insertTupleNonVirtual(joined);
            }
        }
    }

    return (true);
}
Example #5
0
bool NestLoopExecutor::p_init(AbstractPlanNode* abstract_node, const catalog::Database* catalog_db, int* tempTableMemoryInBytes) {
    VOLT_TRACE("init NestLoop Executor");
    assert(tempTableMemoryInBytes);

    NestLoopPlanNode* node = dynamic_cast<NestLoopPlanNode*>(abstract_node);
    assert(node);

    // produce the fully joined schema relying on a later projection
    // to narrow the output later as required.
    assert(node->getInputTables().size() == 2);
    const TupleSchema *first = node->getInputTables()[0]->schema();
    const TupleSchema *second = node->getInputTables()[1]->schema();
    TupleSchema *schema = TupleSchema::createTupleSchema(first, second);

    int combinedColumnCount = first->columnCount() + second->columnCount();
    std::string *columnNames = new std::string[combinedColumnCount];
    std::vector<int> outputColumnGuids;
    int index = 0;

    for (int ctr = 0; ctr < 2; ctr++) {
        assert(node->getInputTables()[ctr]);
        for (int col_ctr = 0, col_cnt = node->getInputTables()[ctr]->columnCount();
             col_ctr < col_cnt;
             col_ctr++, index++)
        {
            outputColumnGuids.
                push_back(node->getChildren()[ctr]->getOutputColumnGuids()[col_ctr]);
            columnNames[index] = node->getInputTables()[ctr]->columnName(col_ctr);
        }
    }

    // Set the mapping of column names to column indexes in output tables
    node->setOutputColumnGuids(outputColumnGuids);

    // create the output table
    node->setOutputTable(
        TableFactory::getTempTable(
            node->getInputTables()[0]->databaseId(), "temp", schema, columnNames, tempTableMemoryInBytes));

    // for each tuple value expression in the predicate, determine
    // which tuple is being represented. Tuple could come from outer
    // table or inner table. Configure the predicate to use the correct
    // eval() tuple parameter. By convention, eval's first parameter
    // will always be the outer table and its second parameter the inner
    const AbstractExpression *predicate = node->getPredicate();
    std::stack<const AbstractExpression*> stack;
    while (predicate != NULL) {
        const AbstractExpression *left = predicate->getLeft();
        const AbstractExpression *right = predicate->getRight();

        if (right != NULL) {
            if (right->getExpressionType() == EXPRESSION_TYPE_VALUE_TUPLE) {
                if (!assignTupleValueIndex(const_cast<AbstractExpression*>(right),
                                           node->getInputTables()[0]->name(),
                                           node->getInputTables()[1]->name())) {
                    delete [] columnNames;
                    return false;
                }
            }
            // remember the right node - must visit its children
            stack.push(right);
        }
        if (left != NULL) {
            if (left->getExpressionType() == EXPRESSION_TYPE_VALUE_TUPLE) {
                if (!assignTupleValueIndex(const_cast<AbstractExpression*>(left),
                                           node->getInputTables()[0]->name(),
                                           node->getInputTables()[1]->name())) {
                    delete [] columnNames;
                    return false;
                }
            }
        }

        predicate = left;
        if (!predicate && !stack.empty()) {
            predicate = stack.top();
            stack.pop();
        }
    }

    delete[] columnNames;
    return true;
}
Example #6
0
bool NestLoopExecutor::p_execute(const NValueArray &params) {
    VOLT_DEBUG("executing NestLoop...");

    NestLoopPlanNode* node = dynamic_cast<NestLoopPlanNode*>(m_abstractNode);
    assert(node);
    assert(node->getInputTableCount() == 2);

    // output table must be a temp table
    assert(m_tmpOutputTable);

    Table* outer_table = node->getInputTable();
    assert(outer_table);

    Table* inner_table = node->getInputTable(1);
    assert(inner_table);

    VOLT_TRACE ("input table left:\n %s", outer_table->debug().c_str());
    VOLT_TRACE ("input table right:\n %s", inner_table->debug().c_str());

    //
    // Pre Join Expression
    //
    AbstractExpression *preJoinPredicate = node->getPreJoinPredicate();
    if (preJoinPredicate) {
        VOLT_TRACE ("Pre Join predicate: %s", preJoinPredicate == NULL ?
                    "NULL" : preJoinPredicate->debug(true).c_str());
    }
    //
    // Join Expression
    //
    AbstractExpression *joinPredicate = node->getJoinPredicate();
    if (joinPredicate) {
        VOLT_TRACE ("Join predicate: %s", joinPredicate == NULL ?
                    "NULL" : joinPredicate->debug(true).c_str());
    }
    //
    // Where Expression
    //
    AbstractExpression *wherePredicate = node->getWherePredicate();
    if (wherePredicate) {
        VOLT_TRACE ("Where predicate: %s", wherePredicate == NULL ?
                    "NULL" : wherePredicate->debug(true).c_str());
    }

    // Join type
    JoinType join_type = node->getJoinType();
    assert(join_type == JOIN_TYPE_INNER || join_type == JOIN_TYPE_LEFT);

    LimitPlanNode* limit_node = dynamic_cast<LimitPlanNode*>(node->getInlinePlanNode(PLAN_NODE_TYPE_LIMIT));
    int limit = -1;
    int offset = -1;
    if (limit_node) {
        limit_node->getLimitAndOffsetByReference(params, limit, offset);
    }

    int outer_cols = outer_table->columnCount();
    int inner_cols = inner_table->columnCount();
    TableTuple outer_tuple(node->getInputTable(0)->schema());
    TableTuple inner_tuple(node->getInputTable(1)->schema());
    const TableTuple& null_tuple = m_null_tuple.tuple();

    TableIterator iterator0 = outer_table->iteratorDeletingAsWeGo();
    int tuple_ctr = 0;
    int tuple_skipped = 0;
    ProgressMonitorProxy pmp(m_engine, this, inner_table);

    TableTuple join_tuple;
    if (m_aggExec != NULL) {
        VOLT_TRACE("Init inline aggregate...");
        const TupleSchema * aggInputSchema = node->getTupleSchemaPreAgg();
        join_tuple = m_aggExec->p_execute_init(params, &pmp, aggInputSchema, m_tmpOutputTable);
    } else {
        join_tuple = m_tmpOutputTable->tempTuple();
    }

    bool earlyReturned = false;
    while ((limit == -1 || tuple_ctr < limit) && iterator0.next(outer_tuple)) {
        pmp.countdownProgress();

        // populate output table's temp tuple with outer table's values
        // probably have to do this at least once - avoid doing it many
        // times per outer tuple
        join_tuple.setNValues(0, outer_tuple, 0, outer_cols);

        // did this loop body find at least one match for this tuple?
        bool match = false;
        // For outer joins if outer tuple fails pre-join predicate
        // (join expression based on the outer table only)
        // it can't match any of inner tuples
        if (preJoinPredicate == NULL || preJoinPredicate->eval(&outer_tuple, NULL).isTrue()) {

            // By default, the delete as we go flag is false.
            TableIterator iterator1 = inner_table->iterator();
            while ((limit == -1 || tuple_ctr < limit) && iterator1.next(inner_tuple)) {
                pmp.countdownProgress();
                // Apply join filter to produce matches for each outer that has them,
                // then pad unmatched outers, then filter them all
                if (joinPredicate == NULL || joinPredicate->eval(&outer_tuple, &inner_tuple).isTrue()) {
                    match = true;
                    // Filter the joined tuple
                    if (wherePredicate == NULL || wherePredicate->eval(&outer_tuple, &inner_tuple).isTrue()) {
                        // Check if we have to skip this tuple because of offset
                        if (tuple_skipped < offset) {
                            tuple_skipped++;
                            continue;
                        }
                        ++tuple_ctr;
                        // Matched! Complete the joined tuple with the inner column values.
                        join_tuple.setNValues(outer_cols, inner_tuple, 0, inner_cols);
                        if (m_aggExec != NULL) {
                            if (m_aggExec->p_execute_tuple(join_tuple)) {
                                // Get enough rows for LIMIT
                                earlyReturned = true;
                                break;
                            }
                        } else {
                            m_tmpOutputTable->insertTempTuple(join_tuple);
                            pmp.countdownProgress();
                        }
                    }
                }
            } // END INNER WHILE LOOP
        } // END IF PRE JOIN CONDITION

        //
        // Left Outer Join
        //
        if (join_type == JOIN_TYPE_LEFT && !match && (limit == -1 || tuple_ctr < limit)) {
            // Still needs to pass the filter
            if (wherePredicate == NULL || wherePredicate->eval(&outer_tuple, &null_tuple).isTrue()) {
                // Check if we have to skip this tuple because of offset
                if (tuple_skipped < offset) {
                    tuple_skipped++;
                    continue;
                }
                ++tuple_ctr;
                join_tuple.setNValues(outer_cols, null_tuple, 0, inner_cols);
                if (m_aggExec != NULL) {
                    if (m_aggExec->p_execute_tuple(join_tuple)) {
                        earlyReturned = true;
                    }
                } else {
                    m_tmpOutputTable->insertTempTuple(join_tuple);
                    pmp.countdownProgress();
                }
            }
        } // END IF LEFT OUTER JOIN

        if (earlyReturned) {
            // Get enough rows for LIMIT inlined with aggregation
            break;
        }

    } // END OUTER WHILE LOOP

    if (m_aggExec != NULL) {
        m_aggExec->p_execute_finish();
    }

    cleanupInputTempTable(inner_table);
    cleanupInputTempTable(outer_table);

    return (true);
}