예제 #1
0
bool DistinctExecutor::p_execute(const NValueArray &params) {
    DistinctPlanNode* node = dynamic_cast<DistinctPlanNode*>(m_abstractNode);
    assert(node);
    Table* output_table = node->getOutputTable();
    assert(output_table);
    Table* input_table = node->getInputTables()[0];
    assert(input_table);

    TableIterator iterator = input_table->iterator();
    TableTuple tuple(input_table->schema());

    // substitute params for distinct expression
    AbstractExpression *distinctExpression = node->getDistinctExpression();
    distinctExpression->substitute(params);

    std::set<NValue, NValue::ltNValue> found_values;
    while (iterator.next(tuple)) {
        //
        // Check whether this value already exists in our list
        //
        NValue tuple_value = distinctExpression->eval(&tuple, NULL);
        if (found_values.find(tuple_value) == found_values.end()) {
            found_values.insert(tuple_value);
            if (!output_table->insertTuple(tuple)) {
                VOLT_ERROR("Failed to insert tuple from input table '%s' into"
                           " output table '%s'",
                           input_table->name().c_str(),
                           output_table->name().c_str());
                return false;
            }
        }
    }

    return true;
}
예제 #2
0
 bool operator()(TableTuple ta, TableTuple tb)
 {
     for (size_t i = 0; i < m_keyCount; ++i)
     {
         AbstractExpression* k = m_keys[i];
         SortDirectionType dir = m_dirs[i];
         int cmp = k->eval(&ta, NULL).compare(k->eval(&tb, NULL));
         if (dir == SORT_DIRECTION_TYPE_ASC)
         {
             if (cmp < 0) return true;
             if (cmp > 0) return false;
         }
         else if (dir == SORT_DIRECTION_TYPE_DESC)
         {
             if (cmp < 0) return false;
             if (cmp > 0) return true;
         }
         else
         {
             throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION,
                                           "Attempted to sort using"
                                           " SORT_DIRECTION_TYPE_INVALID");
         }
     }
     return false; // ta == tb on these keys
 }
예제 #3
0
TupleSchema* AbstractPlanNode::generateTupleSchema(const std::vector<SchemaColumn*>& outputSchema)
{
    int schema_size = static_cast<int>(outputSchema.size());
    vector<voltdb::ValueType> columnTypes;
    vector<int32_t> columnSizes;
    vector<bool> columnAllowNull(schema_size, true);
    vector<bool> columnInBytes;

    for (int i = 0; i < schema_size; i++)
    {
        //TODO: SchemaColumn is a sad little class that holds an expression pointer,
        // a column name that only really comes in handy in one quirky special case,
        // (see UpdateExecutor::p_init) and a bunch of other stuff that doesn't get used.
        // Someone should put that class out of our misery.
        SchemaColumn* col = outputSchema[i];
        AbstractExpression * expr = col->getExpression();
        columnTypes.push_back(expr->getValueType());
        columnSizes.push_back(expr->getValueSize());
        columnInBytes.push_back(expr->getInBytes());
    }

    TupleSchema* schema =
        TupleSchema::createTupleSchema(columnTypes, columnSizes,
                                       columnAllowNull, columnInBytes);
    return schema;
}
예제 #4
0
void test_interpreter()
{
	ContextInterpreter* pContext = new ContextInterpreter();
	AbstractExpression* pTe = new TerminalExpression("hello world");
	AbstractExpression* pNte = new NonterminalExpression(pTe, 3);

	pNte->Interpreter(*pContext);
}
예제 #5
0
int main(int argc,char* argv[]) { 
	Context* c = new Context();
	AbstractExpression* te = new TerminalExpression("hello");
	AbstractExpression* nte = new NonterminalExpression(te,2);
	nte->Interpret(*c);
	delete nte;
	delete c;
	return 0; 
}
예제 #6
0
AbstractExpression *AbstractExpression::CreateExpressionTree(
    json_spirit::Object &obj) {
  AbstractExpression *expr =
      AbstractExpression::CreateExpressionTreeRecurse(obj);

  if (expr) expr->InitParamShortCircuits();

  return expr;
}
예제 #7
0
bool MaterializedScanExecutor::p_execute(const NValueArray &params) {
    MaterializedScanPlanNode* node = dynamic_cast<MaterializedScanPlanNode*>(m_abstractNode);
    assert(node);

    // output table has one column
    Table* output_table = node->getOutputTable();
    TableTuple& tmptup = output_table->tempTuple();
    assert(output_table);
    assert ((int)output_table->columnCount() == 1);

    // get the output type
    const TupleSchema::ColumnInfo *columnInfo = output_table->schema()->getColumnInfo(0);
    ValueType outputType = columnInfo->getVoltType();
    bool outputCantBeNull = !columnInfo->allowNull;

    AbstractExpression* rowsExpression = node->getTableRowsExpression();
    assert(rowsExpression);

    // get array nvalue
    NValue arrayNValue = rowsExpression->eval();

    SortDirectionType sort_direction = node->getSortDirection();

    // make a set to eliminate unique values in O(nlogn) time
    std::vector<NValue> sortedUniques;

    // iterate over the array of values and build a sorted/deduped set of
    // values that don't overflow or violate unique constaints
    arrayNValue.castAndSortAndDedupArrayForInList(outputType, sortedUniques);

    // insert all items in the set in order
    if (sort_direction != SORT_DIRECTION_TYPE_DESC) {
        std::vector<NValue>::const_iterator iter;
        for (iter = sortedUniques.begin(); iter != sortedUniques.end(); iter++) {
            if ((*iter).isNull() && outputCantBeNull) {
                continue;
            }
            tmptup.setNValue(0, *iter);
            output_table->insertTuple(tmptup);
        }
    } else {
        std::vector<NValue>::reverse_iterator reverse_iter;
        for (reverse_iter = sortedUniques.rbegin(); reverse_iter != sortedUniques.rend(); reverse_iter++) {
            if ((*reverse_iter).isNull() && outputCantBeNull) {
                continue;
            }
            tmptup.setNValue(0, *reverse_iter);
            output_table->insertTuple(tmptup);
        }
    }

    VOLT_TRACE("\n%s\n", output_table->debug().c_str());
    VOLT_DEBUG("Finished Materializing a Table");

    return true;
}
예제 #8
0
TEST_F(FilterTest, ComplexFilter) {

    // WHERE val1=1 AND val2=2 AND val3=3 AND val4=4

    // shared_ptr<AbstractExpression> equal1
    //     = ComparisonExpression::getInstance(EXPRESSION_TYPE_COMPARE_EQUAL, TupleValueExpression::getInstance(1), ConstantValueExpression::getInstance(voltdb::Value::newBigIntValue(1)));
    // shared_ptr<AbstractExpression> equal2
    //     = ComparisonExpression::getInstance(EXPRESSION_TYPE_COMPARE_EQUAL, TupleValueExpression::getInstance(2), ConstantValueExpression::getInstance(voltdb::Value::newBigIntValue(2)));
    // shared_ptr<AbstractExpression> equal3
    //     = ComparisonExpression::getInstance(EXPRESSION_TYPE_COMPARE_EQUAL, TupleValueExpression::getInstance(3), ConstantValueExpression::getInstance(voltdb::Value::newBigIntValue(3)));
    // shared_ptr<AbstractExpression> equal4
    //     = ComparisonExpression::getInstance(EXPRESSION_TYPE_COMPARE_EQUAL, TupleValueExpression::getInstance(4), ConstantValueExpression::getInstance(voltdb::Value::newBigIntValue(4)));
    //
    // shared_ptr<AbstractExpression> predicate3
    //     = ConjunctionExpression::getInstance(EXPRESSION_TYPE_CONJUNCTION_AND, equal3, equal4);
    // shared_ptr<AbstractExpression> predicate2
    //     = ConjunctionExpression::getInstance(EXPRESSION_TYPE_CONJUNCTION_AND, equal2, predicate3);
    //
    // ConjunctionExpression predicate(EXPRESSION_TYPE_CONJUNCTION_AND, equal1, predicate2);

    AbstractExpression *equal1 = comparisonFactory(EXPRESSION_TYPE_COMPARE_EQUAL,
                                                   new TupleValueExpression(1, std::string("tablename"), std::string("colname")),
                                                   constantValueFactory(ValueFactory::getBigIntValue(1)));

    AbstractExpression *equal2 = comparisonFactory(EXPRESSION_TYPE_COMPARE_EQUAL,
                                                   new TupleValueExpression(2, std::string("tablename"), std::string("colname")),
                                                   constantValueFactory(ValueFactory::getBigIntValue(2)));

    AbstractExpression *equal3 = comparisonFactory(EXPRESSION_TYPE_COMPARE_EQUAL,
                                                   new TupleValueExpression(3, std::string("tablename"), std::string("colname")),
                                                   constantValueFactory(ValueFactory::getBigIntValue(3)));

    AbstractExpression *equal4 = comparisonFactory(EXPRESSION_TYPE_COMPARE_EQUAL,
                                                   new TupleValueExpression(4, std::string("tablename"), std::string("colname")),
                                                   constantValueFactory(ValueFactory::getBigIntValue(4)));

    AbstractExpression *predicate3 = conjunctionFactory(EXPRESSION_TYPE_CONJUNCTION_AND, equal3, equal4);
    AbstractExpression *predicate2 = conjunctionFactory(EXPRESSION_TYPE_CONJUNCTION_AND, equal2, predicate3);
    AbstractExpression *predicate = conjunctionFactory(EXPRESSION_TYPE_CONJUNCTION_AND, equal1, predicate2);


    // ::printf("\nFilter:%s\n", predicate->debug().c_str());

    int count = 0;
    TableIterator iter = table->iterator();
    TableTuple match(table->schema());
    while (iter.next(match)) {
        if (predicate->eval(&match, NULL).isTrue()) {
            //::printf("  match:%s\n", match->debug(table).c_str());
            ++count;
        }
    }
    ASSERT_EQ(5, count);

    delete predicate;
}
예제 #9
0
// ------------------------------------------------------------------
// SERIALIZATION METHODS
// ------------------------------------------------------------------
AbstractExpression*
AbstractExpression::buildExpressionTree(json_spirit::Object &obj)
{
    AbstractExpression * exp =
      AbstractExpression::buildExpressionTree_recurse(obj);

    if (exp)
        exp->initParamShortCircuits();
    return exp;
}
예제 #10
0
// ------------------------------------------------------------------
// SERIALIZATION METHODS
// ------------------------------------------------------------------
AbstractExpression*
AbstractExpression::buildExpressionTree(PlannerDomValue obj)
{
    AbstractExpression * exp =
      AbstractExpression::buildExpressionTree_recurse(obj);

    if (exp)
        exp->initParamShortCircuits();
    return exp;
}
int main()
{
    Context* con1 = new Context("Hello world.");
    AbstractExpression* tinter = new TerminalExpression();
    AbstractExpression* nont = new NonTerminalExpression();

    tinter->Interpreter(con1);
    nont->Interpreter(con1);

    return 0;
}
예제 #12
0
bool AbstractExecutor::TupleComparer::operator()(TableTuple ta, TableTuple tb) const
{
    for (size_t i = 0; i < m_keyCount; ++i)
    {
        AbstractExpression* k = m_keys[i];
        SortDirectionType dir = m_dirs[i];
        int cmp = k->eval(&ta, NULL).compare(k->eval(&tb, NULL));

        if (cmp < 0) return (dir == SORT_DIRECTION_TYPE_ASC);
        if (cmp > 0) return (dir == SORT_DIRECTION_TYPE_DESC);
    }
    return false; // ta == tb on these keys
}
예제 #13
0
TEST_F(FilterTest, SubstituteFilter) {

    // WHERE id <= 20 AND val4=$1

    // shared_ptr<AbstractExpression> equal1
    //     = ComparisonExpression::getInstance(EXPRESSION_TYPE_COMPARE_LESSTHANOREQUALTO, TupleValueExpression::getInstance(0), ConstantValueExpression::getInstance(voltdb::Value::newBigIntValue(20)));
    //
    // shared_ptr<AbstractExpression> equal2
    //     = ComparisonExpression::getInstance(EXPRESSION_TYPE_COMPARE_EQUAL, TupleValueExpression::getInstance(4), ParameterValueExpression::getInstance(0));
    //
    // ConjunctionExpression predicate(EXPRESSION_TYPE_CONJUNCTION_AND, equal1, equal2);

    AbstractExpression *tv1 = new TupleValueExpression(0, std::string("tablename"), std::string("colname"));
    AbstractExpression *cv1 = constantValueFactory(ValueFactory::getBigIntValue(20));
    AbstractExpression *equal1 = comparisonFactory(EXPRESSION_TYPE_COMPARE_LESSTHANOREQUALTO, tv1, cv1);

    AbstractExpression *tv2 = new TupleValueExpression(4, std::string("tablename"), std::string("colname"));
    AbstractExpression *pv2 = parameterValueFactory(0);
    AbstractExpression *equal2 = comparisonFactory(EXPRESSION_TYPE_COMPARE_EQUAL, tv2, pv2);

    AbstractExpression *predicate = conjunctionFactory(EXPRESSION_TYPE_CONJUNCTION_AND, equal1, equal2);

    // ::printf("\nFilter:%s\n", predicate->debug().c_str());

    for (int64_t implantedValue = 1; implantedValue < 5; ++implantedValue) {
        NValueArray params(1);
        params[0] = ValueFactory::getBigIntValue(implantedValue);
        predicate->substitute(params);
        // ::printf("\nSubstituted Filter:%s\n", predicate->debug().c_str());
        // ::printf("\tLEFT:  %s\n", predicate->getLeft()->debug().c_str());
        // ::printf("\tRIGHT: %s\n", predicate->getRight()->debug().c_str());

        int count = 0;
        TableIterator iter = table->iterator();
        TableTuple match(table->schema());
        while (iter.next(match)) {
            if (predicate->eval(&match, NULL).isTrue()) {
                ++count;
            }
        }
        ASSERT_EQ(3, count);
    }

    delete predicate;
}
예제 #14
0
/*
 *
 * Helper method responsible for inserting the results of the
 * aggregation into a new tuple in the output table as well as passing
 * through any additional columns from the input table.
 */
inline void WindowFunctionExecutor::insertOutputTuple()
{
    TableTuple& tempTuple = m_tmpOutputTable->tempTuple();

    // We copy the aggregate values into the output tuple,
    // then the passthrough columns.
    WindowAggregate** aggs = m_aggregateRow->getAggregates();
    for (int ii = 0; ii < getAggregateCount(); ii++) {
        NValue result = aggs[ii]->finalize(tempTuple.getSchema()->columnType(ii));
        tempTuple.setNValue(ii, result);
    }

    VOLT_TRACE("Setting passthrough columns");
    size_t tupleSize = tempTuple.sizeInValues();
    for (int ii = getAggregateCount(); ii < tupleSize; ii += 1) {
        AbstractExpression *expr = m_outputColumnExpressions[ii];
        tempTuple.setNValue(ii, expr->eval(&(m_aggregateRow->getPassThroughTuple())));
    }

    m_tmpOutputTable->insertTempTuple(tempTuple);
    VOLT_TRACE("output_table:\n%s", m_tmpOutputTable->debug().c_str());
}
예제 #15
0
int main(int argc, char* argv[])
{
	//生成表达式
	AbstractExpression* expression;
	//解析器对象
	Context context;
	//两个变量
	VariableExp* varX = new VariableExp("keyX");
	VariableExp* varY = new VariableExp("keyY");
	/*一个复杂表达式 或(与(常量,变量),与(变量,非(变量)))*/
	expression = new OrExp(
		new AndExp(new ConstantExp(true), varX),
		new AndExp(varY, new NotExp(varX)));
	//在解析器中建立外部名字和值的关联
	context.Assign(varX, false);
	context.Assign(varY, true);
	//递归运算表达式求值
	bool result = expression->Interpret(context);
	cout<<"result: "<<result<<endl;
	printf("Hello World!\n");
	return 0;
}
예제 #16
0
			Expression(const AbstractExpression& expr) : pointer(expr.Clone()) { }
예제 #17
0
/** Given an expression type and a valuetype, find the best
 * templated ctor to invoke. Several helpers, above, aid in this
 * pursuit. Each instantiated expression must consume any
 * class-specific serialization from serialize_io. */
AbstractExpression*
ExpressionUtil::expressionFactory(PlannerDomValue obj,
                  ExpressionType et, ValueType vt, int vs,
                  AbstractExpression* lc,
                  AbstractExpression* rc,
                  const std::vector<AbstractExpression*>* args)
{
    AbstractExpression *ret = NULL;

    switch (et) {

    // Casts
    case (EXPRESSION_TYPE_OPERATOR_CAST):
        ret = castFactory(vt, lc);
    break;

    // Operators
    case (EXPRESSION_TYPE_OPERATOR_PLUS):
    case (EXPRESSION_TYPE_OPERATOR_MINUS):
    case (EXPRESSION_TYPE_OPERATOR_MULTIPLY):
    case (EXPRESSION_TYPE_OPERATOR_DIVIDE):
    case (EXPRESSION_TYPE_OPERATOR_CONCAT):
    case (EXPRESSION_TYPE_OPERATOR_MOD):
    case (EXPRESSION_TYPE_OPERATOR_NOT):
    case (EXPRESSION_TYPE_OPERATOR_IS_NULL):
    case (EXPRESSION_TYPE_OPERATOR_EXISTS):
        ret = operatorFactory(et, lc, rc);
    break;

    // Comparisons
    case (EXPRESSION_TYPE_COMPARE_EQUAL):
    case (EXPRESSION_TYPE_COMPARE_NOTEQUAL):
    case (EXPRESSION_TYPE_COMPARE_LESSTHAN):
    case (EXPRESSION_TYPE_COMPARE_GREATERTHAN):
    case (EXPRESSION_TYPE_COMPARE_LESSTHANOREQUALTO):
    case (EXPRESSION_TYPE_COMPARE_GREATERTHANOREQUALTO):
    case (EXPRESSION_TYPE_COMPARE_LIKE):
    case (EXPRESSION_TYPE_COMPARE_IN):
        ret = comparisonFactory(obj, et, lc, rc);
    break;

    // Conjunctions
    case (EXPRESSION_TYPE_CONJUNCTION_AND):
    case (EXPRESSION_TYPE_CONJUNCTION_OR):
        ret = conjunctionFactory(et, lc, rc);
    break;

    // Functions and pseudo-functions
    case (EXPRESSION_TYPE_FUNCTION): {
        // add the function id
        int functionId = obj.valueForKey("FUNCTION_ID").asInt();

        if (args) {
            ret = functionFactory(functionId, args);
        }

        if ( ! ret) {
            std::string nameString;
            if (obj.hasNonNullKey("NAME")) {
                nameString = obj.valueForKey("NAME").asStr();
            }
            else {
                nameString = "?";
            }
            raiseFunctionFactoryError(nameString, functionId, args);
        }
    }
    break;

    case (EXPRESSION_TYPE_VALUE_VECTOR): {
        // Parse whatever is needed out of obj and pass the pieces to inListFactory
        // to make it easier to unit test independently of the parsing.
        // The first argument is used as the list element type.
        // If the ValueType of the list builder expression needs to be "ARRAY" or something else,
        // a separate element type attribute will have to be serialized and passed in here.
        ret = vectorFactory(vt, args);
    }
    break;

    // Constant Values, parameters, tuples
    case (EXPRESSION_TYPE_VALUE_CONSTANT):
        ret = constantValueFactory(obj, vt, et, lc, rc);
        break;

    case (EXPRESSION_TYPE_VALUE_PARAMETER):
        ret = parameterValueFactory(obj, et, lc, rc);
        break;

    case (EXPRESSION_TYPE_VALUE_TUPLE):
        ret = tupleValueFactory(obj, et, lc, rc);
        break;

    case (EXPRESSION_TYPE_VALUE_TUPLE_ADDRESS):
        ret = new TupleAddressExpression();
        break;
    case (EXPRESSION_TYPE_VALUE_SCALAR):
        ret = new ScalarValueExpression(lc);
        break;
    case (EXPRESSION_TYPE_HASH_RANGE):
        ret = hashRangeFactory(obj);
        break;
    case (EXPRESSION_TYPE_OPERATOR_CASE_WHEN):
        ret = caseWhenFactory(vt, lc, rc);
        break;
    case (EXPRESSION_TYPE_OPERATOR_ALTERNATIVE):
        ret = new OperatorAlternativeExpression(lc, rc);
        break;

    // Subquery
    case (EXPRESSION_TYPE_ROW_SUBQUERY):
    case (EXPRESSION_TYPE_SELECT_SUBQUERY):
        ret = subqueryFactory(et, obj, args);
        break;

        // must handle all known expressions in this factory
    default:

        char message[256];
        snprintf(message,256, "Invalid ExpressionType '%s' (%d) requested from factory",
                expressionToString(et).c_str(), (int)et);
        throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION, message);
    }

    ret->setValueType(vt);
    ret->setValueSize(vs);
    // written thusly to ease testing/inspecting return content.
    VOLT_TRACE("Created expression %p", ret);
    return ret;
}
예제 #18
0
bool SeqScanExecutor::p_execute(const NValueArray &params) {
    SeqScanPlanNode* node = dynamic_cast<SeqScanPlanNode*>(m_abstractNode);
    assert(node);
    Table* output_table = node->getOutputTable();
    assert(output_table);

    Table* input_table = (node->isSubQuery()) ?
            node->getChildren()[0]->getOutputTable():
            node->getTargetTable();

    assert(input_table);

    //* for debug */std::cout << "SeqScanExecutor: node id " << node->getPlanNodeId() <<
    //* for debug */    " input table " << (void*)input_table <<
    //* for debug */    " has " << input_table->activeTupleCount() << " tuples " << std::endl;
    VOLT_TRACE("Sequential Scanning table :\n %s",
               input_table->debug().c_str());
    VOLT_DEBUG("Sequential Scanning table : %s which has %d active, %d"
               " allocated",
               input_table->name().c_str(),
               (int)input_table->activeTupleCount(),
               (int)input_table->allocatedTupleCount());

    //
    // OPTIMIZATION: NESTED PROJECTION
    //
    // Since we have the input params, we need to call substitute to
    // change any nodes in our expression tree to be ready for the
    // projection operations in execute
    //
    int num_of_columns = -1;
    ProjectionPlanNode* projection_node = dynamic_cast<ProjectionPlanNode*>(node->getInlinePlanNode(PLAN_NODE_TYPE_PROJECTION));
    if (projection_node != NULL) {
        num_of_columns = static_cast<int> (projection_node->getOutputColumnExpressions().size());
    }
    //
    // OPTIMIZATION: NESTED LIMIT
    // How nice! We can also cut off our scanning with a nested limit!
    //
    LimitPlanNode* limit_node = dynamic_cast<LimitPlanNode*>(node->getInlinePlanNode(PLAN_NODE_TYPE_LIMIT));

    //
    // OPTIMIZATION:
    //
    // If there is no predicate and no Projection for this SeqScan,
    // then we have already set the node's OutputTable to just point
    // at the TargetTable. Therefore, there is nothing we more we need
    // to do here
    //
    if (node->getPredicate() != NULL || projection_node != NULL ||
        limit_node != NULL || m_aggExec != NULL)
    {
        //
        // Just walk through the table using our iterator and apply
        // the predicate to each tuple. For each tuple that satisfies
        // our expression, we'll insert them into the output table.
        //
        TableTuple tuple(input_table->schema());
        TableIterator iterator = input_table->iteratorDeletingAsWeGo();
        AbstractExpression *predicate = node->getPredicate();

        if (predicate)
        {
            VOLT_TRACE("SCAN PREDICATE A:\n%s\n", predicate->debug(true).c_str());
        }

        int limit = -1;
        int offset = -1;
        if (limit_node) {
            limit_node->getLimitAndOffsetByReference(params, limit, offset);
        }

        int tuple_ctr = 0;
        int tuple_skipped = 0;
        TempTable* output_temp_table = dynamic_cast<TempTable*>(output_table);

        ProgressMonitorProxy pmp(m_engine, this, node->isSubQuery() ? NULL : input_table);
        TableTuple temp_tuple;
        if (m_aggExec != NULL) {
            const TupleSchema * inputSchema = input_table->schema();
            if (projection_node != NULL) {
                inputSchema = projection_node->getOutputTable()->schema();
            }
            temp_tuple = m_aggExec->p_execute_init(params, &pmp,
                    inputSchema, output_temp_table);
        } else {
            temp_tuple = output_temp_table->tempTuple();
        }

        while ((limit == -1 || tuple_ctr < limit) && iterator.next(tuple))
        {
            VOLT_TRACE("INPUT TUPLE: %s, %d/%d\n",
                       tuple.debug(input_table->name()).c_str(), tuple_ctr,
                       (int)input_table->activeTupleCount());
            pmp.countdownProgress();
            //
            // For each tuple we need to evaluate it against our predicate
            //
            if (predicate == NULL || predicate->eval(&tuple, NULL).isTrue())
            {
                // Check if we have to skip this tuple because of offset
                if (tuple_skipped < offset) {
                    tuple_skipped++;
                    continue;
                }
                ++tuple_ctr;

                //
                // Nested Projection
                // Project (or replace) values from input tuple
                //
                if (projection_node != NULL)
                {
                    VOLT_TRACE("inline projection...");
                    for (int ctr = 0; ctr < num_of_columns; ctr++) {
                        NValue value = projection_node->getOutputColumnExpressions()[ctr]->eval(&tuple, NULL);
                        temp_tuple.setNValue(ctr, value);
                    }

                    if (m_aggExec != NULL) {
                        if (m_aggExec->p_execute_tuple(temp_tuple)) {
                            break;
                        }
                    } else {
                        output_temp_table->insertTupleNonVirtual(temp_tuple);
                    }
                }
                else
                {
                    if (m_aggExec != NULL) {
                        if (m_aggExec->p_execute_tuple(tuple)) {
                            break;
                        }
                    } else {
                        //
                        // Insert the tuple into our output table
                        //
                        output_temp_table->insertTupleNonVirtual(tuple);
                    }
                }
                pmp.countdownProgress();
            }
        }

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

    }
    //* for debug */std::cout << "SeqScanExecutor: node id " << node->getPlanNodeId() <<
    //* for debug */    " output table " << (void*)output_table <<
    //* for debug */    " put " << output_table->activeTupleCount() << " tuples " << std::endl;
    VOLT_TRACE("\n%s\n", output_table->debug().c_str());
    VOLT_DEBUG("Finished Seq scanning");

    return true;
}
예제 #19
0
/** Given an expression type and a valuetype, find the best
 * templated ctor to invoke. Several helpers, above, aid in this
 * pursuit. Each instantiated expression must consume any
 * class-specific serialization from serialize_io. */
AbstractExpression*
ExpressionUtil::expressionFactory(json_spirit::Object &obj,
                  ExpressionType et, ValueType vt, int vs,
                  AbstractExpression* lc,
                  AbstractExpression* rc,
                  const std::vector<AbstractExpression*>* args)
{
    AbstractExpression *ret = NULL;

    switch (et) {

        // Operators
    case (EXPRESSION_TYPE_OPERATOR_PLUS):
    case (EXPRESSION_TYPE_OPERATOR_MINUS):
    case (EXPRESSION_TYPE_OPERATOR_MULTIPLY):
    case (EXPRESSION_TYPE_OPERATOR_DIVIDE):
    case (EXPRESSION_TYPE_OPERATOR_CONCAT):
    case (EXPRESSION_TYPE_OPERATOR_MOD):
    case (EXPRESSION_TYPE_OPERATOR_CAST):
    case (EXPRESSION_TYPE_OPERATOR_NOT):
    case (EXPRESSION_TYPE_OPERATOR_IS_NULL):
        ret = operatorFactory(et, lc, rc);
    break;

    // Comparisons
    case (EXPRESSION_TYPE_COMPARE_EQUAL):
    case (EXPRESSION_TYPE_COMPARE_NOTEQUAL):
    case (EXPRESSION_TYPE_COMPARE_LESSTHAN):
    case (EXPRESSION_TYPE_COMPARE_GREATERTHAN):
    case (EXPRESSION_TYPE_COMPARE_LESSTHANOREQUALTO):
    case (EXPRESSION_TYPE_COMPARE_GREATERTHANOREQUALTO):
    case (EXPRESSION_TYPE_COMPARE_LIKE):
        ret = comparisonFactory( et, lc, rc);
    break;

    // Conjunctions
    case (EXPRESSION_TYPE_CONJUNCTION_AND):
    case (EXPRESSION_TYPE_CONJUNCTION_OR):
        ret = conjunctionFactory(et, lc, rc);
    break;

    // Functions and pseudo-functions
    case (EXPRESSION_TYPE_FUNCTION): {
        // add the function id
        json_spirit::Value functionIdValue = json_spirit::find_value(obj, "FUNCTION_ID");
        if (functionIdValue == json_spirit::Value::null) {
            throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION,
                                          "ExpressionUtil::"
                                          "expressionFactory:"
                                          " Couldn't find FUNCTION_ID value");
        }
        int functionId = functionIdValue.get_int();

        ret = functionFactory(functionId, args);
        if ( ! ret) {
            json_spirit::Value functionNameValue = json_spirit::find_value(obj, "NAME");
            std::string nameString;
            if (functionNameValue == json_spirit::Value::null) {
                nameString = "?";
            } else {
                nameString = functionNameValue.get_str();
            }

            char aliasBuffer[256];
            json_spirit::Value functionAliasValue = json_spirit::find_value(obj, "ALIAS");
            if (functionAliasValue == json_spirit::Value::null) {
                aliasBuffer[0] = '\0';
            } else {
                std::string aliasString = functionAliasValue.get_str();
                snprintf(aliasBuffer, sizeof(aliasBuffer), " aliased to '%s'", aliasString.c_str());
            }

            char fn_message[1024];
            snprintf(fn_message, sizeof(fn_message),
                     "SQL function '%s'%s with ID (%d) with (%d) parameters is not implemented in VoltDB (or may have been incorrectly parsed)",
                     nameString.c_str(), aliasBuffer, functionId, (int)args->size());
            throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION, fn_message);
        }
    }
    break;

    // Constant Values, parameters, tuples
    case (EXPRESSION_TYPE_VALUE_CONSTANT):
        ret = constantValueFactory(obj, vt, et, lc, rc);
        break;

    case (EXPRESSION_TYPE_VALUE_PARAMETER):
        ret = parameterValueFactory(obj, et, lc, rc);
        break;

    case (EXPRESSION_TYPE_VALUE_TUPLE):
        ret = tupleValueFactory(obj, et, lc, rc);
        break;

    case (EXPRESSION_TYPE_VALUE_TUPLE_ADDRESS):
        ret = new TupleAddressExpression();
        break;

        // must handle all known expressions in this factory
    default:

        char message[256];
        snprintf(message,256, "Invalid ExpressionType '%s' (%d) requested from factory",
                expressionToString(et).c_str(), (int)et);
        throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION, message);
    }

    ret->setValueType(vt);
    ret->setValueSize(vs);
    // written thusly to ease testing/inspecting return content.
    VOLT_TRACE("Created expression %p", ret);
    return ret;
}
예제 #20
0
 bool interpret( Context* context)
 {
   return (pOperand1_->interpret(context) == pOperand2_->interpret(context)); 
 }
예제 #21
0
/** Given an expression type and a valuetype, find the best
 * templated ctor to invoke. Several helpers, above, aid in this
 * pursuit. Each instantiated expression must consume any
 * class-specific serialization from serialize_io. */
AbstractExpression*
ExpressionUtil::expressionFactory(PlannerDomValue obj,
                  ExpressionType et, ValueType vt, int vs,
                  AbstractExpression* lc,
                  AbstractExpression* rc,
                  const std::vector<AbstractExpression*>* args)
{
    AbstractExpression *ret = NULL;

    switch (et) {

    // Casts
    case (EXPRESSION_TYPE_OPERATOR_CAST):
        ret = castFactory(vt, lc);
    break;

    // Operators
    case (EXPRESSION_TYPE_OPERATOR_PLUS):
    case (EXPRESSION_TYPE_OPERATOR_MINUS):
    case (EXPRESSION_TYPE_OPERATOR_MULTIPLY):
    case (EXPRESSION_TYPE_OPERATOR_DIVIDE):
    case (EXPRESSION_TYPE_OPERATOR_CONCAT):
    case (EXPRESSION_TYPE_OPERATOR_MOD):
    case (EXPRESSION_TYPE_OPERATOR_NOT):
    case (EXPRESSION_TYPE_OPERATOR_IS_NULL):
        ret = operatorFactory(et, lc, rc);
    break;

    // Comparisons
    case (EXPRESSION_TYPE_COMPARE_EQUAL):
    case (EXPRESSION_TYPE_COMPARE_NOTEQUAL):
    case (EXPRESSION_TYPE_COMPARE_LESSTHAN):
    case (EXPRESSION_TYPE_COMPARE_GREATERTHAN):
    case (EXPRESSION_TYPE_COMPARE_LESSTHANOREQUALTO):
    case (EXPRESSION_TYPE_COMPARE_GREATERTHANOREQUALTO):
    case (EXPRESSION_TYPE_COMPARE_LIKE):
    case (EXPRESSION_TYPE_COMPARE_IN):
        ret = comparisonFactory( et, lc, rc);
    break;

    // Conjunctions
    case (EXPRESSION_TYPE_CONJUNCTION_AND):
    case (EXPRESSION_TYPE_CONJUNCTION_OR):
        ret = conjunctionFactory(et, lc, rc);
    break;

    // Functions and pseudo-functions
    case (EXPRESSION_TYPE_FUNCTION): {
        // add the function id
        int functionId = obj.valueForKey("FUNCTION_ID").asInt();

        ret = functionFactory(functionId, args);
        if ( ! ret) {
            std::string nameString;
            if (obj.hasNonNullKey("NAME")) {
                nameString = obj.valueForKey("NAME").asStr();
            }
            else {
                nameString = "?";
            }

            char aliasBuffer[256];
            if (obj.hasNonNullKey("ALIAS")) {
                std::string aliasString = obj.valueForKey("ALIAS").asStr();
                snprintf(aliasBuffer, sizeof(aliasBuffer), " aliased to '%s'", aliasString.c_str());
            }

            char fn_message[1024];
            snprintf(fn_message, sizeof(fn_message),
                     "SQL function '%s'%s with ID (%d) with (%d) parameters is not implemented in VoltDB (or may have been incorrectly parsed)",
                     nameString.c_str(), aliasBuffer, functionId, (int)args->size());
            throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION, fn_message);
        }
    }
    break;

    case (EXPRESSION_TYPE_INLISTBUILDER): {
        // Parse whatever is needed out of obj and pass the pieces to inListFactory
        // to make it easier to unit test independently of the parsing.
        // The first argument is used as the list element type.
        // If the ValueType of the list builder expression needs to be "ARRAY" or something else,
        // a separate element type attribute will have to be serialized and passed in here.
        ret = inListFactory(vt, args);
    }
    break;

    // Constant Values, parameters, tuples
    case (EXPRESSION_TYPE_VALUE_CONSTANT):
        ret = constantValueFactory(obj, vt, et, lc, rc);
        break;

    case (EXPRESSION_TYPE_VALUE_PARAMETER):
        ret = parameterValueFactory(obj, et, lc, rc);
        break;

    case (EXPRESSION_TYPE_VALUE_TUPLE):
        ret = tupleValueFactory(obj, et, lc, rc);
        break;

    case (EXPRESSION_TYPE_VALUE_TUPLE_ADDRESS):
        ret = new TupleAddressExpression();
        break;
    case (EXPRESSION_TYPE_HASH_RANGE):
        ret = hashRangeFactory(obj);
        break;
        // must handle all known expressions in this factory
    default:

        char message[256];
        snprintf(message,256, "Invalid ExpressionType '%s' (%d) requested from factory",
                expressionToString(et).c_str(), (int)et);
        throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION, message);
    }

    ret->setValueType(vt);
    ret->setValueSize(vs);
    // written thusly to ease testing/inspecting return content.
    VOLT_TRACE("Created expression %p", ret);
    return ret;
}
예제 #22
0
bool IndexScanExecutor::p_execute(const NValueArray &params)
{
    assert(m_node);
    assert(m_node == dynamic_cast<IndexScanPlanNode*>(m_abstractNode));

    // update local target table with its most recent reference
    Table* targetTable = m_node->getTargetTable();
    TableIndex *tableIndex = targetTable->index(m_node->getTargetIndexName());
    IndexCursor indexCursor(tableIndex->getTupleSchema());

    TableTuple searchKey(tableIndex->getKeySchema());
    searchKey.moveNoHeader(m_searchKeyBackingStore);

    assert(m_lookupType != INDEX_LOOKUP_TYPE_EQ ||
            searchKey.getSchema()->columnCount() == m_numOfSearchkeys);

    int activeNumOfSearchKeys = m_numOfSearchkeys;
    IndexLookupType localLookupType = m_lookupType;
    SortDirectionType localSortDirection = m_sortDirection;

    //
    // INLINE LIMIT
    //
    LimitPlanNode* limit_node = dynamic_cast<LimitPlanNode*>(m_abstractNode->getInlinePlanNode(PLAN_NODE_TYPE_LIMIT));

    TableTuple temp_tuple;
    ProgressMonitorProxy pmp(m_engine, this);
    if (m_aggExec != NULL) {
        const TupleSchema * inputSchema = tableIndex->getTupleSchema();
        if (m_projectionNode != NULL) {
            inputSchema = m_projectionNode->getOutputTable()->schema();
        }
        temp_tuple = m_aggExec->p_execute_init(params, &pmp, inputSchema, m_outputTable);
    } else {
        temp_tuple = m_outputTable->tempTuple();
    }

    // Short-circuit an empty scan
    if (m_node->isEmptyScan()) {
        VOLT_DEBUG ("Empty Index Scan :\n %s", m_outputTable->debug().c_str());
        if (m_aggExec != NULL) {
            m_aggExec->p_execute_finish();
        }
        return true;
    }

    //
    // SEARCH KEY
    //
    bool earlyReturnForSearchKeyOutOfRange = false;

    searchKey.setAllNulls();
    VOLT_TRACE("Initial (all null) search key: '%s'", searchKey.debugNoHeader().c_str());

    for (int ctr = 0; ctr < activeNumOfSearchKeys; ctr++) {
        NValue candidateValue = m_searchKeyArray[ctr]->eval(NULL, NULL);
        if (candidateValue.isNull()) {
            // when any part of the search key is NULL, the result is false when it compares to anything.
            // do early return optimization, our index comparator may not handle null comparison correctly.
            earlyReturnForSearchKeyOutOfRange = true;
            break;
        }

        try {
            searchKey.setNValue(ctr, candidateValue);
        }
        catch (const SQLException &e) {
            // This next bit of logic handles underflow, overflow and search key length
            // exceeding variable length column size (variable lenght mismatch) when
            // setting up the search keys.
            // e.g. TINYINT > 200 or INT <= 6000000000
            // VarChar(3 bytes) < "abcd" or VarChar(3) > "abbd"

            // re-throw if not an overflow, underflow or variable length mismatch
            // currently, it's expected to always be an overflow or underflow
            if ((e.getInternalFlags() & (SQLException::TYPE_OVERFLOW | SQLException::TYPE_UNDERFLOW | SQLException::TYPE_VAR_LENGTH_MISMATCH)) == 0) {
                throw e;
            }

            // handle the case where this is a comparison, rather than equality match
            // comparison is the only place where the executor might return matching tuples
            // e.g. TINYINT < 1000 should return all values
            if ((localLookupType != INDEX_LOOKUP_TYPE_EQ) &&
                    (ctr == (activeNumOfSearchKeys - 1))) {

                if (e.getInternalFlags() & SQLException::TYPE_OVERFLOW) {
                    if ((localLookupType == INDEX_LOOKUP_TYPE_GT) ||
                            (localLookupType == INDEX_LOOKUP_TYPE_GTE)) {

                        // gt or gte when key overflows returns nothing except inline agg
                        earlyReturnForSearchKeyOutOfRange = true;
                        break;
                    }
                    else {
                        // for overflow on reverse scan, we need to
                        // do a forward scan to find the correct start
                        // point, which is exactly what LTE would do.
                        // so, set the lookupType to LTE and the missing
                        // searchkey will be handled by extra post filters
                        localLookupType = INDEX_LOOKUP_TYPE_LTE;
                    }
                }
                if (e.getInternalFlags() & SQLException::TYPE_UNDERFLOW) {
                    if ((localLookupType == INDEX_LOOKUP_TYPE_LT) ||
                            (localLookupType == INDEX_LOOKUP_TYPE_LTE)) {

                        // lt or lte when key underflows returns nothing except inline agg
                        earlyReturnForSearchKeyOutOfRange = true;
                        break;
                    }
                    else {
                        // don't allow GTE because it breaks null handling
                        localLookupType = INDEX_LOOKUP_TYPE_GT;
                    }
                }
                if (e.getInternalFlags() & SQLException::TYPE_VAR_LENGTH_MISMATCH) {
                    // shrink the search key and add the updated key to search key table tuple
                    searchKey.shrinkAndSetNValue(ctr, candidateValue);
                    // search will be performed on shrinked key, so update lookup operation
                    // to account for it
                    switch (localLookupType) {
                        case INDEX_LOOKUP_TYPE_LT:
                        case INDEX_LOOKUP_TYPE_LTE:
                            localLookupType = INDEX_LOOKUP_TYPE_LTE;
                            break;
                        case INDEX_LOOKUP_TYPE_GT:
                        case INDEX_LOOKUP_TYPE_GTE:
                            localLookupType = INDEX_LOOKUP_TYPE_GT;
                            break;
                        default:
                            assert(!"IndexScanExecutor::p_execute - can't index on not equals");
                            return false;
                    }
                }

                // if here, means all tuples with the previous searchkey
                // columns need to be scanned. Note, if only one column,
                // then all tuples will be scanned. Only exception to this
                // case is setting of search key in search tuple was due
                // to search key length exceeding the search column length
                // of variable length type
                if (!(e.getInternalFlags() & SQLException::TYPE_VAR_LENGTH_MISMATCH)) {
                    // for variable length mismatch error, the needed search key to perform the search
                    // has been generated and added to the search tuple. So no need to decrement
                    // activeNumOfSearchKeys
                    activeNumOfSearchKeys--;
                }
                if (localSortDirection == SORT_DIRECTION_TYPE_INVALID) {
                    localSortDirection = SORT_DIRECTION_TYPE_ASC;
                }
            }
            // if a EQ comparison is out of range, then return no tuples
            else {
                earlyReturnForSearchKeyOutOfRange = true;
                break;
            }
            break;
        }
    }

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

    assert((activeNumOfSearchKeys == 0) || (searchKey.getSchema()->columnCount() > 0));
    VOLT_TRACE("Search key after substitutions: '%s', # of active search keys: %d", searchKey.debugNoHeader().c_str(), activeNumOfSearchKeys);

    //
    // END EXPRESSION
    //
    AbstractExpression* end_expression = m_node->getEndExpression();
    if (end_expression != NULL) {
        VOLT_DEBUG("End Expression:\n%s", end_expression->debug(true).c_str());
    }

    //
    // POST EXPRESSION
    //
    AbstractExpression* post_expression = m_node->getPredicate();
    if (post_expression != NULL) {
        VOLT_DEBUG("Post Expression:\n%s", post_expression->debug(true).c_str());
    }

    // INITIAL EXPRESSION
    AbstractExpression* initial_expression = m_node->getInitialExpression();
    if (initial_expression != NULL) {
        VOLT_DEBUG("Initial Expression:\n%s", initial_expression->debug(true).c_str());
    }

    //
    // SKIP NULL EXPRESSION
    //
    AbstractExpression* skipNullExpr = m_node->getSkipNullPredicate();
    // For reverse scan edge case NULL values and forward scan underflow case.
    if (skipNullExpr != NULL) {
        VOLT_DEBUG("COUNT NULL Expression:\n%s", skipNullExpr->debug(true).c_str());
    }

    //
    // An index scan has three parts:
    //  (1) Lookup tuples using the search key
    //  (2) For each tuple that comes back, check whether the
    //  end_expression is false.
    //  If it is, then we stop scanning. Otherwise...
    //  (3) Check whether the tuple satisfies the post expression.
    //      If it does, then add it to the output table
    //
    // Use our search key to prime the index iterator
    // Now loop through each tuple given to us by the iterator
    //

    TableTuple tuple;
    if (activeNumOfSearchKeys > 0) {
        VOLT_TRACE("INDEX_LOOKUP_TYPE(%d) m_numSearchkeys(%d) key:%s",
                localLookupType, activeNumOfSearchKeys, searchKey.debugNoHeader().c_str());

        if (localLookupType == INDEX_LOOKUP_TYPE_EQ) {
            tableIndex->moveToKey(&searchKey, indexCursor);
        }
        else if (localLookupType == INDEX_LOOKUP_TYPE_GT) {
            tableIndex->moveToGreaterThanKey(&searchKey, indexCursor);
        }
        else if (localLookupType == INDEX_LOOKUP_TYPE_GTE) {
            tableIndex->moveToKeyOrGreater(&searchKey, indexCursor);
        }
        else if (localLookupType == INDEX_LOOKUP_TYPE_LT) {
            tableIndex->moveToLessThanKey(&searchKey, indexCursor);
        }
        else if (localLookupType == INDEX_LOOKUP_TYPE_LTE) {
            // find the entry whose key is greater than search key,
            // do a forward scan using initialExpr to find the correct
            // start point to do reverse scan
            bool isEnd = tableIndex->moveToGreaterThanKey(&searchKey, indexCursor);
            if (isEnd) {
                tableIndex->moveToEnd(false, indexCursor);
            }
            else {
                while (!(tuple = tableIndex->nextValue(indexCursor)).isNullTuple()) {
                    pmp.countdownProgress();
                    if (initial_expression != NULL && !initial_expression->eval(&tuple, NULL).isTrue()) {
                        // just passed the first failed entry, so move 2 backward
                        tableIndex->moveToBeforePriorEntry(indexCursor);
                        break;
                    }
                }
                if (tuple.isNullTuple()) {
                    tableIndex->moveToEnd(false, indexCursor);
                }
            }
        }
        else {
            return false;
        }
    }
    else {
        bool toStartActually = (localSortDirection != SORT_DIRECTION_TYPE_DESC);
        tableIndex->moveToEnd(toStartActually, indexCursor);
    }

    int tuple_ctr = 0;
    int tuples_skipped = 0;     // for offset
    int limit = -1;
    int offset = -1;
    if (limit_node != NULL) {
        limit_node->getLimitAndOffsetByReference(params, limit, offset);
    }

    //
    // We have to different nextValue() methods for different lookup types
    //
    while ((limit == -1 || tuple_ctr < limit) &&
            ((localLookupType == INDEX_LOOKUP_TYPE_EQ &&
                    !(tuple = tableIndex->nextValueAtKey(indexCursor)).isNullTuple()) ||
                    ((localLookupType != INDEX_LOOKUP_TYPE_EQ || activeNumOfSearchKeys == 0) &&
                            !(tuple = tableIndex->nextValue(indexCursor)).isNullTuple()))) {
        if (tuple.isPendingDelete()) {
            continue;
        }
        VOLT_TRACE("LOOPING in indexscan: tuple: '%s'\n", tuple.debug("tablename").c_str());

        pmp.countdownProgress();
        //
        // First check to eliminate the null index rows for UNDERFLOW case only
        //
        if (skipNullExpr != NULL) {
            if (skipNullExpr->eval(&tuple, NULL).isTrue()) {
                VOLT_DEBUG("Index scan: find out null rows or columns.");
                continue;
            } else {
                skipNullExpr = NULL;
            }
        }
        //
        // First check whether the end_expression is now false
        //
        if (end_expression != NULL && !end_expression->eval(&tuple, NULL).isTrue()) {
            VOLT_TRACE("End Expression evaluated to false, stopping scan");
            break;
        }
        //
        // Then apply our post-predicate to do further filtering
        //
        if (post_expression == NULL || post_expression->eval(&tuple, NULL).isTrue()) {
            //
            // INLINE OFFSET
            //
            if (tuples_skipped < offset)
            {
                tuples_skipped++;
                continue;
            }
            tuple_ctr++;

            if (m_projector.numSteps() > 0) {

                m_projector.exec(temp_tuple, tuple);

                if (m_aggExec != NULL) {
                    if (m_aggExec->p_execute_tuple(temp_tuple)) {
                        break;
                    }
                } else {
                    m_outputTable->insertTupleNonVirtual(temp_tuple);
                }
            }
            else
            {
                if (m_aggExec != NULL) {
                    if (m_aggExec->p_execute_tuple(tuple)) {
                        break;
                    }
                } else {
                    //
                    // Straight Insert
                    //
                    m_outputTable->insertTupleNonVirtual(tuple);
                }
            }
            pmp.countdownProgress();
        }
    }

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


    VOLT_DEBUG ("Index Scanned :\n %s", m_outputTable->debug().c_str());
    return true;
}
예제 #23
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);
}
예제 #24
0
bool AggregateExecutorBase::p_init(AbstractPlanNode*, TempTableLimits* limits)
{
    AggregatePlanNode* node = dynamic_cast<AggregatePlanNode*>(m_abstractNode);
    assert(node);
    assert(node->getChildren().size() == 1);
    assert(node->getChildren()[0] != NULL);

    m_inputExpressions = node->getAggregateInputExpressions();
    for (int i = 0; i < m_inputExpressions.size(); i++) {
        VOLT_DEBUG("\nAGG INPUT EXPRESSION: %s\n",
                   m_inputExpressions[i] ? m_inputExpressions[i]->debug().c_str() : "null");
    }

    /*
     * Find the difference between the set of aggregate output columns
     * (output columns resulting from an aggregate) and output columns.
     * Columns that are not the result of aggregates are being passed
     * through from the input table. Do this extra work here rather then
     * serialize yet more data.
     */
    std::vector<bool> outputColumnsResultingFromAggregates(node->getOutputSchema().size(), false);
    std::vector<int> aggregateOutputColumns = node->getAggregateOutputColumns();
    BOOST_FOREACH(int aOC, aggregateOutputColumns) {
        outputColumnsResultingFromAggregates[aOC] = true;
    }

    /*
     * Now collect the indices in the output table of the pass
     * through columns.
     */
    for (int ii = 0; ii < outputColumnsResultingFromAggregates.size(); ii++) {
        if (outputColumnsResultingFromAggregates[ii] == false) {
            m_passThroughColumns.push_back(ii);
        }
    }

    setTempOutputTable(limits);

    m_aggTypes = node->getAggregates();
    m_distinctAggs = node->getDistinctAggregates();
    m_groupByExpressions = node->getGroupByExpressions();
    node->collectOutputExpressions(m_outputColumnExpressions);
    m_aggregateOutputColumns = node->getAggregateOutputColumns();
    m_prePredicate = node->getPrePredicate();
    m_postPredicate = node->getPostPredicate();

    std::vector<ValueType> groupByColumnTypes;
    std::vector<int32_t> groupByColumnSizes;
    std::vector<bool> groupByColumnAllowNull;
    for (int ii = 0; ii < m_groupByExpressions.size(); ii++) {
        AbstractExpression* expr = m_groupByExpressions[ii];
        groupByColumnTypes.push_back(expr->getValueType());
        groupByColumnSizes.push_back(expr->getValueSize());
        groupByColumnAllowNull.push_back(true);
    }
    m_groupByKeySchema = TupleSchema::createTupleSchema(groupByColumnTypes,
                                                        groupByColumnSizes,
                                                        groupByColumnAllowNull,
                                                        true);
    return true;
}
예제 #25
0
AbstractExpression*
AbstractExpression::buildExpressionTree_recurse(PlannerDomValue obj)
{
    // build a tree recursively from the bottom upwards.
    // when the expression node is instantiated, its type,
    // value and child types will have been discovered.

    ExpressionType peek_type = EXPRESSION_TYPE_INVALID;
    ValueType value_type = VALUE_TYPE_INVALID;
    bool inBytes = false;
    AbstractExpression *left_child = NULL;
    AbstractExpression *right_child = NULL;
    std::vector<AbstractExpression*>* argsVector = NULL;

    // read the expression type
    peek_type = static_cast<ExpressionType>(obj.valueForKey("TYPE").asInt());
    assert(peek_type != EXPRESSION_TYPE_INVALID);

    if (obj.hasNonNullKey("VALUE_TYPE")) {
        int32_t value_type_int = obj.valueForKey("VALUE_TYPE").asInt();
        value_type = static_cast<ValueType>(value_type_int);
        assert(value_type != VALUE_TYPE_INVALID);

        if (obj.hasNonNullKey("IN_BYTES")) {
            inBytes = true;
        }
    }

    // add the value size
    int valueSize = -1;
    if (obj.hasNonNullKey("VALUE_SIZE")) {
        valueSize = obj.valueForKey("VALUE_SIZE").asInt();
    } else {
        // This value size should be consistent with VoltType.java
        valueSize = NValue::getTupleStorageSize(value_type);
    }

    // recurse to children
    try {
        if (obj.hasNonNullKey("LEFT")) {
            PlannerDomValue leftValue = obj.valueForKey("LEFT");
            left_child = AbstractExpression::buildExpressionTree_recurse(leftValue);
        }
        if (obj.hasNonNullKey("RIGHT")) {
            PlannerDomValue rightValue = obj.valueForKey("RIGHT");
            right_child = AbstractExpression::buildExpressionTree_recurse(rightValue);
        }

        // NULL argsVector corresponds to a missing ARGS value
        // vs. an empty argsVector which corresponds to an empty array ARGS value.
        // Different expression types could assert either a NULL or non-NULL argsVector initializer.
        if (obj.hasNonNullKey("ARGS")) {
            PlannerDomValue argsArray = obj.valueForKey("ARGS");
            argsVector = new std::vector<AbstractExpression*>();
            for (int i = 0; i < argsArray.arrayLen(); i++) {
                PlannerDomValue argValue = argsArray.valueAtIndex(i);
                AbstractExpression* argExpr = AbstractExpression::buildExpressionTree_recurse(argValue);
                argsVector->push_back(argExpr);
            }
        }

        // invoke the factory. obviously it has to handle null children.
        // pass it the serialization stream in case a subclass has more
        // to read. yes, the per-class data really does follow the
        // child serializations.
        AbstractExpression* finalExpr = ExpressionUtil::expressionFactory(obj, peek_type, value_type, valueSize,
                left_child, right_child, argsVector);

        finalExpr->setInBytes(inBytes);

        return finalExpr;
    }
    catch (const SerializableEEException &ex) {
        delete left_child;
        delete right_child;
        delete argsVector;
        throw;
    }
}
예제 #26
0
bool SeqScanExecutor::p_execute(const NValueArray &params) {
    SeqScanPlanNode* node = dynamic_cast<SeqScanPlanNode*>(m_abstractNode);
    assert(node);
    Table* output_table = node->getOutputTable();
    assert(output_table);
    Table* target_table = dynamic_cast<Table*>(node->getTargetTable());
    assert(target_table);
    //cout << "SeqScanExecutor: node id" << node->getPlanNodeId() << endl;
    VOLT_TRACE("Sequential Scanning table :\n %s",
               target_table->debug().c_str());
    VOLT_DEBUG("Sequential Scanning table : %s which has %d active, %d"
               " allocated, %d used tuples",
               target_table->name().c_str(),
               (int)target_table->activeTupleCount(),
               (int)target_table->allocatedTupleCount(),
               (int)target_table->usedTupleCount());

    //
    // OPTIMIZATION: NESTED PROJECTION
    //
    // Since we have the input params, we need to call substitute to
    // change any nodes in our expression tree to be ready for the
    // projection operations in execute
    //
    int num_of_columns = (int)output_table->columnCount();
    ProjectionPlanNode* projection_node = dynamic_cast<ProjectionPlanNode*>(node->getInlinePlanNode(PLAN_NODE_TYPE_PROJECTION));
    if (projection_node != NULL) {
        for (int ctr = 0; ctr < num_of_columns; ctr++) {
            assert(projection_node->getOutputColumnExpressions()[ctr]);
            projection_node->getOutputColumnExpressions()[ctr]->substitute(params);
        }
    }

    //
    // OPTIMIZATION: NESTED LIMIT
    // How nice! We can also cut off our scanning with a nested limit!
    //
    int limit = -1;
    int offset = -1;
    LimitPlanNode* limit_node = dynamic_cast<LimitPlanNode*>(node->getInlinePlanNode(PLAN_NODE_TYPE_LIMIT));
    if (limit_node != NULL) {
        limit_node->getLimitAndOffsetByReference(params, limit, offset);
    }

    //
    // OPTIMIZATION:
    //
    // If there is no predicate and no Projection for this SeqScan,
    // then we have already set the node's OutputTable to just point
    // at the TargetTable. Therefore, there is nothing we more we need
    // to do here
    //
    if (node->getPredicate() != NULL || projection_node != NULL ||
        limit_node != NULL)
    {
        //
        // Just walk through the table using our iterator and apply
        // the predicate to each tuple. For each tuple that satisfies
        // our expression, we'll insert them into the output table.
        //
        TableTuple tuple(target_table->schema());
        TableIterator iterator = target_table->iterator();
        AbstractExpression *predicate = node->getPredicate();
        VOLT_TRACE("SCAN PREDICATE A:\n%s\n", predicate->debug(true).c_str());

        if (predicate)
        {
            predicate->substitute(params);
            assert(predicate != NULL);
            VOLT_DEBUG("SCAN PREDICATE B:\n%s\n",
                       predicate->debug(true).c_str());
        }

        int tuple_ctr = 0;
        int tuple_skipped = 0;
        while (iterator.next(tuple))
        {
            VOLT_TRACE("INPUT TUPLE: %s, %d/%d\n",
                       tuple.debug(target_table->name()).c_str(), tuple_ctr,
                       (int)target_table->activeTupleCount());
            //
            // For each tuple we need to evaluate it against our predicate
            //
            if (predicate == NULL || predicate->eval(&tuple, NULL).isTrue())
            {
                // Check if we have to skip this tuple because of offset
                if (tuple_skipped < offset) {
                    tuple_skipped++;
                    continue;
                }

                //
                // Nested Projection
                // Project (or replace) values from input tuple
                //
                if (projection_node != NULL)
                {
                    TableTuple &temp_tuple = output_table->tempTuple();
                    for (int ctr = 0; ctr < num_of_columns; ctr++)
                    {
                        NValue value =
                            projection_node->
                          getOutputColumnExpressions()[ctr]->eval(&tuple, NULL);
                        temp_tuple.setNValue(ctr, value);
                    }
                    if (!output_table->insertTuple(temp_tuple))
                    {
                        VOLT_ERROR("Failed to insert tuple from table '%s' into"
                                   " output table '%s'",
                                   target_table->name().c_str(),
                                   output_table->name().c_str());
                        return false;
                    }
                }
                else
                {
                    //
                    // Insert the tuple into our output table
                    //
                    if (!output_table->insertTuple(tuple)) {
                        VOLT_ERROR("Failed to insert tuple from table '%s' into"
                                   " output table '%s'",
                                   target_table->name().c_str(),
                                   output_table->name().c_str());
                        return false;
                    }
                }
                ++tuple_ctr;
                // Check whether we have gone past our limit
                if (limit >= 0 && tuple_ctr >= limit) {
                    break;
                }
            }
        }
    }
    VOLT_TRACE("\n%s\n", output_table->debug().c_str());
    VOLT_DEBUG("Finished Seq scanning");

    return true;
}
예제 #27
0
bool IndexScanExecutor::p_execute(const NValueArray &params)
{
    assert(m_node);
    assert(m_node == dynamic_cast<IndexScanPlanNode*>(m_abstractNode));
    assert(m_outputTable);
    assert(m_outputTable == static_cast<TempTable*>(m_node->getOutputTable()));

    // update local target table with its most recent reference
    Table* targetTable = m_node->getTargetTable();
    TableIndex *tableIndex = targetTable->index(m_node->getTargetIndexName());
    TableTuple searchKey(tableIndex->getKeySchema());
    searchKey.moveNoHeader(m_searchKeyBackingStore);

    assert(m_lookupType != INDEX_LOOKUP_TYPE_EQ ||
            searchKey.getSchema()->columnCount() == m_numOfSearchkeys);

    int activeNumOfSearchKeys = m_numOfSearchkeys;
    IndexLookupType localLookupType = m_lookupType;
    SortDirectionType localSortDirection = m_sortDirection;

    // INLINE PROJECTION
    // Set params to expression tree via substitute()
    assert(m_numOfColumns == m_outputTable->columnCount());
    if (m_projectionNode != NULL && m_projectionAllTupleArray == NULL)
    {
        for (int ctr = 0; ctr < m_numOfColumns; ctr++)
        {
            assert(m_projectionNode->getOutputColumnExpressions()[ctr]);
            m_projectionExpressions[ctr]->substitute(params);
            assert(m_projectionExpressions[ctr]);
        }
    }

    //
    // INLINE LIMIT
    //
    LimitPlanNode* limit_node = dynamic_cast<LimitPlanNode*>(m_abstractNode->getInlinePlanNode(PLAN_NODE_TYPE_LIMIT));

    //
    // SEARCH KEY
    //
    searchKey.setAllNulls();
    VOLT_TRACE("Initial (all null) search key: '%s'", searchKey.debugNoHeader().c_str());
    for (int ctr = 0; ctr < activeNumOfSearchKeys; ctr++) {
        m_searchKeyArray[ctr]->substitute(params);
        NValue candidateValue = m_searchKeyArray[ctr]->eval(NULL, NULL);
        try {
            searchKey.setNValue(ctr, candidateValue);
        }
        catch (const SQLException &e) {
            // This next bit of logic handles underflow and overflow while
            // setting up the search keys.
            // e.g. TINYINT > 200 or INT <= 6000000000

            // re-throw if not an overflow or underflow
            // currently, it's expected to always be an overflow or underflow
            if ((e.getInternalFlags() & (SQLException::TYPE_OVERFLOW | SQLException::TYPE_UNDERFLOW)) == 0) {
                throw e;
            }

            // handle the case where this is a comparison, rather than equality match
            // comparison is the only place where the executor might return matching tuples
            // e.g. TINYINT < 1000 should return all values
            if ((localLookupType != INDEX_LOOKUP_TYPE_EQ) &&
                (ctr == (activeNumOfSearchKeys - 1))) {

                if (e.getInternalFlags() & SQLException::TYPE_OVERFLOW) {
                    if ((localLookupType == INDEX_LOOKUP_TYPE_GT) ||
                        (localLookupType == INDEX_LOOKUP_TYPE_GTE)) {

                        // gt or gte when key overflows returns nothing
                        return true;
                    }
                    else {
                        // for overflow on reverse scan, we need to
                        // do a forward scan to find the correct start
                        // point, which is exactly what LTE would do.
                        // so, set the lookupType to LTE and the missing
                        // searchkey will be handled by extra post filters
                        localLookupType = INDEX_LOOKUP_TYPE_LTE;
                    }
                }
                if (e.getInternalFlags() & SQLException::TYPE_UNDERFLOW) {
                    if ((localLookupType == INDEX_LOOKUP_TYPE_LT) ||
                        (localLookupType == INDEX_LOOKUP_TYPE_LTE)) {

                        // lt or lte when key underflows returns nothing
                        return true;
                    }
                    else {
                        // don't allow GTE because it breaks null handling
                        localLookupType = INDEX_LOOKUP_TYPE_GT;
                    }
                }

                // if here, means all tuples with the previous searchkey
                // columns need to be scaned. Note, if only one column,
                // then all tuples will be scanned
                activeNumOfSearchKeys--;
                if (localSortDirection == SORT_DIRECTION_TYPE_INVALID) {
                    localSortDirection = SORT_DIRECTION_TYPE_ASC;
                }
            }
            // if a EQ comparison is out of range, then return no tuples
            else {
                return true;
            }
            break;
        }
    }
    assert((activeNumOfSearchKeys == 0) || (searchKey.getSchema()->columnCount() > 0));
    VOLT_TRACE("Search key after substitutions: '%s'", searchKey.debugNoHeader().c_str());

    //
    // END EXPRESSION
    //
    AbstractExpression* end_expression = m_node->getEndExpression();
    if (end_expression != NULL) {
        end_expression->substitute(params);
        VOLT_DEBUG("End Expression:\n%s", end_expression->debug(true).c_str());
    }

    //
    // POST EXPRESSION
    //
    AbstractExpression* post_expression = m_node->getPredicate();
    if (post_expression != NULL) {
        post_expression->substitute(params);
        VOLT_DEBUG("Post Expression:\n%s", post_expression->debug(true).c_str());
    }

    // INITIAL EXPRESSION
    AbstractExpression* initial_expression = m_node->getInitialExpression();
    if (initial_expression != NULL) {
        initial_expression->substitute(params);
        VOLT_DEBUG("Initial Expression:\n%s", initial_expression->debug(true).c_str());
    }

    //
    // SKIP NULL EXPRESSION
    //
    AbstractExpression* skipNullExpr = m_node->getSkipNullPredicate();
    // For reverse scan edge case NULL values and forward scan underflow case.
    if (skipNullExpr != NULL) {
        skipNullExpr->substitute(params);
        VOLT_DEBUG("COUNT NULL Expression:\n%s", skipNullExpr->debug(true).c_str());
    }

    ProgressMonitorProxy pmp(m_engine, targetTable);
    //
    // An index scan has three parts:
    //  (1) Lookup tuples using the search key
    //  (2) For each tuple that comes back, check whether the
    //  end_expression is false.
    //  If it is, then we stop scanning. Otherwise...
    //  (3) Check whether the tuple satisfies the post expression.
    //      If it does, then add it to the output table
    //
    // Use our search key to prime the index iterator
    // Now loop through each tuple given to us by the iterator
    //

    TableTuple tuple;
    if (activeNumOfSearchKeys > 0) {
        VOLT_TRACE("INDEX_LOOKUP_TYPE(%d) m_numSearchkeys(%d) key:%s",
                   localLookupType, activeNumOfSearchKeys, searchKey.debugNoHeader().c_str());

        if (localLookupType == INDEX_LOOKUP_TYPE_EQ) {
            tableIndex->moveToKey(&searchKey);
        }
        else if (localLookupType == INDEX_LOOKUP_TYPE_GT) {
            tableIndex->moveToGreaterThanKey(&searchKey);
        }
        else if (localLookupType == INDEX_LOOKUP_TYPE_GTE) {
            tableIndex->moveToKeyOrGreater(&searchKey);
        } else if (localLookupType == INDEX_LOOKUP_TYPE_LT) {
            tableIndex->moveToLessThanKey(&searchKey);
        } else if (localLookupType == INDEX_LOOKUP_TYPE_LTE) {
            // find the entry whose key is greater than search key,
            // do a forward scan using initialExpr to find the correct
            // start point to do reverse scan
            bool isEnd = tableIndex->moveToGreaterThanKey(&searchKey);
            if (isEnd) {
                tableIndex->moveToEnd(false);
            } else {
                while (!(tuple = tableIndex->nextValue()).isNullTuple()) {
                    pmp.countdownProgress();
                    if (initial_expression != NULL && !initial_expression->eval(&tuple, NULL).isTrue()) {
                        // just passed the first failed entry, so move 2 backward
                        tableIndex->moveToBeforePriorEntry();
                        break;
                    }
                }
                if (tuple.isNullTuple()) {
                    tableIndex->moveToEnd(false);
                }
            }
        }
        else {
            return false;
        }
    } else {
        bool toStartActually = (localSortDirection != SORT_DIRECTION_TYPE_DESC);
        tableIndex->moveToEnd(toStartActually);
    }

    int tuple_ctr = 0;
    int tuples_skipped = 0;     // for offset
    int limit = -1;
    int offset = -1;
    if (limit_node != NULL) {
        limit_node->getLimitAndOffsetByReference(params, limit, offset);
    }

    //
    // We have to different nextValue() methods for different lookup types
    //
    while ((limit == -1 || tuple_ctr < limit) &&
           ((localLookupType == INDEX_LOOKUP_TYPE_EQ &&
             !(tuple = tableIndex->nextValueAtKey()).isNullTuple()) ||
           ((localLookupType != INDEX_LOOKUP_TYPE_EQ || activeNumOfSearchKeys == 0) &&
            !(tuple = tableIndex->nextValue()).isNullTuple()))) {
        VOLT_TRACE("LOOPING in indexscan: tuple: '%s'\n", tuple.debug("tablename").c_str());
        pmp.countdownProgress();
        //
        // First check to eliminate the null index rows for UNDERFLOW case only
        //
        if (skipNullExpr != NULL) {
            if (skipNullExpr->eval(&tuple, NULL).isTrue()) {
                VOLT_DEBUG("Index scan: find out null rows or columns.");
                continue;
            } else {
                skipNullExpr = NULL;
            }
        }
        //
        // First check whether the end_expression is now false
        //
        if (end_expression != NULL && !end_expression->eval(&tuple, NULL).isTrue()) {
            VOLT_TRACE("End Expression evaluated to false, stopping scan");
            break;
        }
        //
        // Then apply our post-predicate to do further filtering
        //
        if (post_expression == NULL || post_expression->eval(&tuple, NULL).isTrue()) {
            //
            // INLINE OFFSET
            //
            if (tuples_skipped < offset)
            {
                tuples_skipped++;
                continue;
            }
            tuple_ctr++;

            if (m_projectionNode != NULL)
            {
                TableTuple &temp_tuple = m_outputTable->tempTuple();
                if (m_projectionAllTupleArray != NULL)
                {
                    VOLT_TRACE("sweet, all tuples");
                    for (int ctr = m_numOfColumns - 1; ctr >= 0; --ctr) {
                        temp_tuple.setNValue(ctr, tuple.getNValue(m_projectionAllTupleArray[ctr]));
                    }
                }
                else
                {
                    for (int ctr = m_numOfColumns - 1; ctr >= 0; --ctr) {
                        temp_tuple.setNValue(ctr, m_projectionExpressions[ctr]->eval(&tuple, NULL));
                    }
                }
                m_outputTable->insertTupleNonVirtual(temp_tuple);
            }
            else
                //
                // Straight Insert
                //
            {
                //
                // Try to put the tuple into our output table
                //
                m_outputTable->insertTupleNonVirtual(tuple);
            }
            pmp.countdownProgress();
        }
    }

    VOLT_DEBUG ("Index Scanned :\n %s", m_outputTable->debug().c_str());
    return true;
}
예제 #28
0
bool IndexCountExecutor::p_execute(const NValueArray &params)
{
    assert(m_node);
    assert(m_node == dynamic_cast<IndexCountPlanNode*>(m_abstractNode));
    assert(m_outputTable);
    assert(m_outputTable == static_cast<TempTable*>(m_node->getOutputTable()));
    assert(m_targetTable);
    assert(m_targetTable == m_node->getTargetTable());
    VOLT_DEBUG("IndexCount: %s.%s\n", m_targetTable->name().c_str(),
               m_index->getName().c_str());

    int activeNumOfSearchKeys = m_numOfSearchkeys;
    IndexLookupType localLookupType = m_lookupType;
    bool searchKeyUnderflow = false, endKeyOverflow = false;
    // Overflow cases that can return early without accessing the index need this
    // default 0 count as their result.
    TableTuple& tmptup = m_outputTable->tempTuple();
    tmptup.setNValue(0, ValueFactory::getBigIntValue( 0 ));

    //
    // SEARCH KEY
    //
    if (m_numOfSearchkeys != 0) {
        m_searchKey.setAllNulls();
        VOLT_DEBUG("<Index Count>Initial (all null) search key: '%s'", m_searchKey.debugNoHeader().c_str());
        for (int ctr = 0; ctr < activeNumOfSearchKeys; ctr++) {
            m_searchKeyArray[ctr]->substitute(params);
            NValue candidateValue = m_searchKeyArray[ctr]->eval(NULL, NULL);
            try {
                m_searchKey.setNValue(ctr, candidateValue);
            }
            catch (const SQLException &e) {
                // This next bit of logic handles underflow and overflow while
                // setting up the search keys.
                // e.g. TINYINT > 200 or INT <= 6000000000

                // re-throw if not an overflow or underflow
                // currently, it's expected to always be an overflow or underflow
                if ((e.getInternalFlags() & (SQLException::TYPE_OVERFLOW | SQLException::TYPE_UNDERFLOW)) == 0) {
                    throw e;
                }

                // handle the case where this is a comparison, rather than equality match
                // comparison is the only place where the executor might return matching tuples
                // e.g. TINYINT < 1000 should return all values

                if ((localLookupType != INDEX_LOOKUP_TYPE_EQ) &&
                    (ctr == (activeNumOfSearchKeys - 1))) {
                    assert (localLookupType == INDEX_LOOKUP_TYPE_GT || localLookupType == INDEX_LOOKUP_TYPE_GTE);

                    if (e.getInternalFlags() & SQLException::TYPE_OVERFLOW) {
                        m_outputTable->insertTuple(tmptup);
                        return true;
                    } else if (e.getInternalFlags() & SQLException::TYPE_UNDERFLOW) {
                        searchKeyUnderflow = true;
                        break;
                    } else {
                        throw e;
                    }
                }
                // if a EQ comparision is out of range, then return no tuples
                else {
                    m_outputTable->insertTuple(tmptup);
                    return true;
                }
                break;
            }
        }
        VOLT_TRACE("Search key after substitutions: '%s'", m_searchKey.debugNoHeader().c_str());
    }

    if (m_numOfEndkeys != 0) {
        //
        // END KEY
        //
        m_endKey.setAllNulls();
        VOLT_DEBUG("Initial (all null) end key: '%s'", m_endKey.debugNoHeader().c_str());
        for (int ctr = 0; ctr < m_numOfEndkeys; ctr++) {
            m_endKeyArray[ctr]->substitute(params);
            NValue endKeyValue = m_endKeyArray[ctr]->eval(NULL, NULL);
            try {
                m_endKey.setNValue(ctr, endKeyValue);
            }
            catch (const SQLException &e) {
                // This next bit of logic handles underflow and overflow while
                // setting up the search keys.
                // e.g. TINYINT > 200 or INT <= 6000000000

                // re-throw if not an overflow or underflow
                // currently, it's expected to always be an overflow or underflow
                if ((e.getInternalFlags() & (SQLException::TYPE_OVERFLOW | SQLException::TYPE_UNDERFLOW)) == 0) {
                    throw e;
                }

                if (ctr == (m_numOfEndkeys - 1)) {
                    assert (m_endType == INDEX_LOOKUP_TYPE_LT || m_endType == INDEX_LOOKUP_TYPE_LTE);
                    if (e.getInternalFlags() & SQLException::TYPE_UNDERFLOW) {
                        m_outputTable->insertTuple(tmptup);
                        return true;
                    } else if (e.getInternalFlags() & SQLException::TYPE_OVERFLOW) {
                        endKeyOverflow = true;
                        const ValueType type = m_endKey.getSchema()->columnType(ctr);
                        NValue tmpEndKeyValue = ValueFactory::getBigIntValue(getMaxTypeValue(type));
                        m_endKey.setNValue(ctr, tmpEndKeyValue);

                        VOLT_DEBUG("<Index count> end key out of range, MAX value: %ld...\n", (long)getMaxTypeValue(type));
                        break;
                    } else {
                        throw e;
                    }
                }
                // if a EQ comparision is out of range, then return no tuples
                else {
                    m_outputTable->insertTuple(tmptup);
                    return true;
                }
                break;
            }
        }
        VOLT_TRACE("End key after substitutions: '%s'", m_endKey.debugNoHeader().c_str());
    }

    //
    // POST EXPRESSION
    //
    assert (m_node->getPredicate() == NULL);

    assert (m_index);
    assert (m_index == m_targetTable->index(m_node->getTargetIndexName()));
    assert (m_index->isCountableIndex());

    //
    // COUNT NULL EXPRESSION
    //
    AbstractExpression* countNULLExpr = m_node->getSkipNullPredicate();
    // For reverse scan edge case NULL values and forward scan underflow case.
    if (countNULLExpr != NULL) {
        countNULLExpr->substitute(params);
        VOLT_DEBUG("COUNT NULL Expression:\n%s", countNULLExpr->debug(true).c_str());
    }

    bool reverseScanNullEdgeCase = false;
    bool reverseScanMovedIndexToScan = false;
    if (m_numOfSearchkeys < m_numOfEndkeys && (m_endType == INDEX_LOOKUP_TYPE_LT || m_endType == INDEX_LOOKUP_TYPE_LTE)) {
        reverseScanNullEdgeCase = true;
        VOLT_DEBUG("Index count: reverse scan edge null case." );
    }


    // An index count has two cases: unique and non-unique
    int64_t rkStart = 0, rkEnd = 0, rkRes = 0;
    int leftIncluded = 0, rightIncluded = 0;

    if (m_numOfSearchkeys != 0) {
        // Deal with multi-map
        VOLT_DEBUG("INDEX_LOOKUP_TYPE(%d) m_numSearchkeys(%d) key:%s",
                   localLookupType, activeNumOfSearchKeys, m_searchKey.debugNoHeader().c_str());
        if (searchKeyUnderflow == false) {
            if (localLookupType == INDEX_LOOKUP_TYPE_GT) {
                rkStart = m_index->getCounterLET(&m_searchKey, true);
            } else {
                // handle start inclusive cases.
                if (m_index->hasKey(&m_searchKey)) {
                    leftIncluded = 1;
                    rkStart = m_index->getCounterLET(&m_searchKey, false);

                    if (reverseScanNullEdgeCase) {
                        m_index->moveToKeyOrGreater(&m_searchKey);
                        reverseScanMovedIndexToScan = true;
                    }
                } else {
                    rkStart = m_index->getCounterLET(&m_searchKey, true);
                }
            }
        } else {
            // Do not count null row or columns
            m_index->moveToKeyOrGreater(&m_searchKey);
            assert(countNULLExpr);
            long numNULLs = countNulls(countNULLExpr);
            rkStart += numNULLs;
            VOLT_DEBUG("Index count[underflow case]: find out %ld null rows or columns are not counted in.", numNULLs);

        }
    }
    if (reverseScanNullEdgeCase) {
        // reverse scan case
        if (!reverseScanMovedIndexToScan && localLookupType != INDEX_LOOKUP_TYPE_GT) {
            m_index->moveToEnd(true);
        }
        assert(countNULLExpr);
        long numNULLs = countNulls(countNULLExpr);
        rkStart += numNULLs;
        VOLT_DEBUG("Index count[reverse case]: find out %ld null rows or columns are not counted in.", numNULLs);
    }

    if (m_numOfEndkeys != 0) {
        if (endKeyOverflow) {
            rkEnd = m_index->getCounterGET(&m_endKey, true);
        } else {
            IndexLookupType localEndType = m_endType;
            if (localEndType == INDEX_LOOKUP_TYPE_LT) {
                rkEnd = m_index->getCounterGET(&m_endKey, false);
            } else {
                if (m_index->hasKey(&m_endKey)) {
                    rightIncluded = 1;
                    rkEnd = m_index->getCounterGET(&m_endKey, true);
                } else {
                    rkEnd = m_index->getCounterGET(&m_endKey, false);
                }
            }
        }
    } else {
        rkEnd = m_index->getSize();
        rightIncluded = 1;
    }
    rkRes = rkEnd - rkStart - 1 + leftIncluded + rightIncluded;
    VOLT_DEBUG("Index Count ANSWER %ld = %ld - %ld - 1 + %d + %d\n", (long)rkRes, (long)rkEnd, (long)rkStart, leftIncluded, rightIncluded);
    tmptup.setNValue(0, ValueFactory::getBigIntValue( rkRes ));
    m_outputTable->insertTuple(tmptup);

    VOLT_DEBUG ("Index Count :\n %s", m_outputTable->debug().c_str());
    return true;
}
예제 #29
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);
}
예제 #30
0
파일: main.cpp 프로젝트: chenxin0123/Demos
///一些应用提供了内建(Build-In)的脚本或者宏语言来让用户可以定义他们能够在系统 中进行的操作。Interpreter 模式的目的就是使用一个解释器为用户提供一个一门定义语言的 语法表示的解释器,然后通过这个解释器来解释语言中的句子
///Interpreter 模式中使用类来表示文法规则,因此可以很容易实现文法的扩展。另外对于 终结符我们可以使用 Flyweight 模式来实现终结符的共享。
void InterpreterTest() {
    Interpreter_Context* c = new Interpreter_Context();
    AbstractExpression* te = new TerminalExpression("hello");
    AbstractExpression* nte = new NonterminalExpression(te,2);
    nte->Interpret(*c);
}