TEST_F(TableTupleTest, VolatileStandAloneTuple) {
    UniqueEngine engine = UniqueEngineBuilder().build();

    // A schema with
    //    - one fixed size column
    //    - one inlined variable-length column
    //    - one non-inlined variable-length column
    ScopedTupleSchema schema{Tools::buildSchema(VALUE_TYPE_BIGINT,
                                                std::make_pair(VALUE_TYPE_VARCHAR, 12),
                                                std::make_pair(VALUE_TYPE_VARCHAR, 256))};
    StandAloneTupleStorage standAloneTuple{schema.get()};
    TableTuple tuple = standAloneTuple.tuple();
    Tools::setTupleValues(&tuple, int64_t(0), "foo", "foo bar");

    // Stand alone tuples are similar to pool-backed tuples.
    ASSERT_TRUE(tuple.inlinedDataIsVolatile());
    ASSERT_FALSE(tuple.nonInlinedDataIsVolatile());

    NValue nv = tuple.getNValue(0);
    ASSERT_FALSE(nv.getVolatile());

    nv = tuple.getNValue(1);
    ASSERT_TRUE(nv.getVolatile());

    nv = tuple.getNValue(2);
    ASSERT_FALSE(nv.getVolatile());
}
void MaterializedViewMetadata::processTupleDelete(TableTuple &oldTuple) {
    // don't change the view if this tuple doesn't match the predicate
    if (m_filterPredicate && (m_filterPredicate->eval(&oldTuple, NULL).isFalse()))
        return;

    // this will assert if the tuple isn't there as param expected is true
    findExistingTuple(oldTuple, true);

    // clear the tuple that will be built to insert or overwrite
    memset(m_updatedTupleBackingStore, 0, m_target->schema()->tupleLength() + 1);

    //printf("  Existing tuple: %s.\n", m_existingTuple.debugNoHeader().c_str());
    //fflush(stdout);

    // set up the first column, which is a count
    NValue count = m_existingTuple.getNValue(m_groupByColumnCount).op_decrement();

    //printf("  Count is: %d.\n", (int)(m_existingTuple.getSlimValue(m_groupByColumnCount).getBigInt()));
    //fflush(stdout);

    // check if we should remove the tuple
    if (count.isZero()) {
        m_target->deleteTuple(m_existingTuple, true);
        return;
    }
    // assume from here that we're just updating the existing row

    int colindex = 0;
    // set up the first n columns, based on group-by columns
    for (colindex = 0; colindex < m_groupByColumnCount; colindex++) {
        m_updatedTuple.setNValue(colindex, oldTuple.getNValue(m_groupByColumns[colindex]));
    }

    m_updatedTuple.setNValue(colindex, count);
    colindex++;

    // set values for the other columns
    for (int i = colindex; i < m_outputColumnCount; i++) {
        NValue oldValue = oldTuple.getNValue(m_outputColumnSrcTableIndexes[i]);
        NValue existingValue = m_existingTuple.getNValue(i);

        if (m_outputColumnAggTypes[i] == EXPRESSION_TYPE_AGGREGATE_SUM) {
            m_updatedTuple.setNValue(i, existingValue.op_subtract(oldValue));
        }
        else if (m_outputColumnAggTypes[i] == EXPRESSION_TYPE_AGGREGATE_COUNT) {
            m_updatedTuple.setNValue(i, existingValue.op_decrement());
        }
        else {
            throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION,
                                          "Error in materialized view table"
                                          " update.");
        }
    }

    // update the row
    // shouldn't need to update indexes as this shouldn't ever change the key
    m_target->updateTuple(m_updatedTuple, m_existingTuple, false);
}
void MaterializedViewMetadata::processTupleInsert(TableTuple &newTuple) {
    // don't change the view if this tuple doesn't match the predicate
    if (m_filterPredicate
        && (m_filterPredicate->eval(&newTuple, NULL).isFalse()))
        return;

    bool exists = findExistingTuple(newTuple);
    if (!exists) {
        // create a blank tuple
        m_existingTuple.move(m_emptyTupleBackingStore);
    }

    // clear the tuple that will be built to insert or overwrite
    memset(m_updatedTupleBackingStore, 0, m_target->schema()->tupleLength() + 1);

    int colindex = 0;
    // set up the first n columns, based on group-by columns
    for (colindex = 0; colindex < m_groupByColumnCount; colindex++) {
        m_updatedTuple.setNValue(colindex,
                                 newTuple.getNValue(m_groupByColumns[colindex]));
    }

    // set up the next column, which is a count
    m_updatedTuple.setNValue(colindex,
                             m_existingTuple.getNValue(colindex).op_increment());
    colindex++;

    // set values for the other columns
    for (int i = colindex; i < m_outputColumnCount; i++) {
        NValue newValue = newTuple.getNValue(m_outputColumnSrcTableIndexes[i]);
        NValue existingValue = m_existingTuple.getNValue(i);

        if (m_outputColumnAggTypes[i] == EXPRESSION_TYPE_AGGREGATE_SUM) {
            m_updatedTuple.setNValue(i, newValue.op_add(existingValue));
        }
        else if (m_outputColumnAggTypes[i] == EXPRESSION_TYPE_AGGREGATE_COUNT) {
            m_updatedTuple.setNValue(i, existingValue.op_increment());
        }
        else {
            char message[128];
            sprintf(message, "Error in materialized view table update for"
                    " col %d. Expression type %d", i, m_outputColumnAggTypes[i]);
            throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION,
                                          message);
        }
    }

    // update or insert the row
    if (exists) {
        // shouldn't need to update indexes as this shouldn't ever change the
        // key
        m_target->updateTuple(m_updatedTuple, m_existingTuple, false);
    }
    else {
        m_target->insertTuple(m_updatedTuple);
    }
}
TEST_F(TableTupleTest, VolatileTempTuplePersistent) {
    UniqueEngine engine = UniqueEngineBuilder().build();

    // A schema with
    //    - one fixed-length column
    //    - one inlined variable-length column
    //    - one non-inlined variable-length column
    TupleSchema *schema = Tools::buildSchema(VALUE_TYPE_BIGINT,
                                             std::make_pair(VALUE_TYPE_VARCHAR, 12),
                                             std::make_pair(VALUE_TYPE_VARCHAR, 256));
    std::vector<std::string> columnNames{"id", "inlined", "noninlined"};
    char signature[20];
    std::unique_ptr<Table> table{TableFactory::getPersistentTable(0,
                                                                  "perstbl",
                                                                  schema,
                                                                  columnNames,
                                                                  signature)};
    TableTuple tuple = table->tempTuple();
    Tools::setTupleValues(&tuple, int64_t(0), "foo", "foo bar");

    ASSERT_TRUE(tuple.inlinedDataIsVolatile());
    ASSERT_FALSE(tuple.nonInlinedDataIsVolatile());

    NValue nv = tuple.getNValue(0);
    ASSERT_FALSE(nv.getVolatile());

    nv = tuple.getNValue(1);
    ASSERT_TRUE(nv.getVolatile());

    nv = tuple.getNValue(2);
    ASSERT_FALSE(nv.getVolatile());

    table->insertTuple(tuple);
    TableIterator it = table->iterator();
    TableTuple iterTuple{schema};
    while (it.next(iterTuple)) {
        // Regular, TupleBlock-backed tuples are never volatile.
        ASSERT_FALSE(iterTuple.inlinedDataIsVolatile());
        ASSERT_FALSE(iterTuple.nonInlinedDataIsVolatile());

        nv = iterTuple.getNValue(0);
        ASSERT_FALSE(nv.getVolatile());

        nv = iterTuple.getNValue(1);
        ASSERT_FALSE(nv.getVolatile());

        nv = iterTuple.getNValue(2);
        ASSERT_FALSE(nv.getVolatile());
    }
}
Beispiel #5
0
int WindowFunctionExecutor::compareTuples(const TableTuple &tuple1,
                                          const TableTuple &tuple2) const {
    const TupleSchema *schema = tuple1.getSchema();
    assert (schema == tuple2.getSchema());

    for (int ii = schema->columnCount() - 1; ii >= 0; --ii) {
        int cmp = tuple2.getNValue(ii)
            .compare(tuple1.getNValue(ii));
        if (cmp != 0) {
            return cmp;
        }
    }
    return 0;

}
TEST_F(TableTupleFilterTest, tableTupleFilterTest)
{
    static const int MARKER = 33;

    TempTable* table = getTempTable();
    TableTupleFilter tableFilter;
    tableFilter.init(table);

    int tuplePerBlock = table->getTuplesPerBlock();
    // make sure table spans more than one block
    ASSERT_TRUE(NUM_OF_TUPLES / tuplePerBlock > 1);

    TableTuple tuple = table->tempTuple();
    TableIterator iterator = table->iterator();

    // iterator over and mark every 5th tuple
    int counter = 0;
    std::multiset<int64_t> control_values;

    while(iterator.next(tuple)) {
        if (++counter % 5 == 0) {
            NValue nvalue = tuple.getNValue(1);
            int64_t value = ValuePeeker::peekBigInt(nvalue);
            control_values.insert(value);
            tableFilter.updateTuple(tuple, MARKER);
        }
    }

    TableTupleFilter_iter<MARKER> endItr = tableFilter.end<MARKER>();
    for (TableTupleFilter_iter<MARKER> itr = tableFilter.begin<MARKER>(); itr != endItr; ++itr) {
            uint64_t tupleAddr = tableFilter.getTupleAddress(*itr);
            tuple.move((char *)tupleAddr);
            ASSERT_TRUE(tuple.isActive());
            NValue nvalue = tuple.getNValue(1);
            int64_t value = ValuePeeker::peekBigInt(nvalue);

            ASSERT_FALSE(control_values.empty());
            auto it = control_values.find(value);
            ASSERT_NE(it, control_values.end());
            control_values.erase(it);
    }
    ASSERT_TRUE(control_values.empty());

}
Beispiel #7
0
void DRTupleStream::updateTxnHash(TableTuple &tuple, int partitionColumn) {
    if (partitionColumn != -1 && m_txnPkHash != LONG_MAX) {
        int64_t txnPkHash = (int64_t)tuple.getNValue(partitionColumn).murmurHash3();
        if (m_txnPkHash == LONG_MIN) {
            m_txnPkHash = txnPkHash;
        }
        else if (txnPkHash != m_txnPkHash) {
            m_txnPkHash = LONG_MAX;
        }
    }
}
NValue compare_tuple(const TableTuple& tuple1, const TableTuple& tuple2)
{
    assert(tuple1.getSchema()->columnCount() == tuple2.getSchema()->columnCount());
    NValue fallback_result = OP::includes_equality() ? NValue::getTrue() : NValue::getFalse();
    int schemaSize = tuple1.getSchema()->columnCount();
    for (int columnIdx = 0; columnIdx < schemaSize; ++columnIdx) {
        NValue value1 = tuple1.getNValue(columnIdx);
        if (value1.isNull()) {
            fallback_result = NValue::getNullValue(VALUE_TYPE_BOOLEAN);
            if (OP::implies_null_for_row()) {
                return fallback_result;
            }
            continue;
        }
        NValue value2 = tuple2.getNValue(columnIdx);
        if (value2.isNull()) {
            fallback_result = NValue::getNullValue(VALUE_TYPE_BOOLEAN);
            if (OP::implies_null_for_row()) {
                return fallback_result;
            }
            continue;
        }
        if (OP::compare_withoutNull(value1, tuple2.getNValue(columnIdx)).isTrue()) {
            if (OP::implies_true_for_row(value1, value2)) {
                // allow early return on strict inequality
                return NValue::getTrue();
            }
        }
        else {
            if (OP::implies_false_for_row(value1, value2)) {
                // allow early return on strict inequality
                return NValue::getFalse();
            }
        }
    }
    // The only cases that have not already short-circuited involve all equal columns.
    // Each op either includes or excludes that particular case.
    return fallback_result;
}
TEST_F(PersistentTableMemStatsTest, UpdateAndUndoTest) {
    initTable(true);
    tableutil::addRandomTuples(m_table, 10);
    int64_t orig_size = m_table->nonInlinedMemorySize();
    //cout << "Original non-inline size: " << orig_size << endl;

    TableTuple tuple(m_tableSchema);
    tableutil::getRandomTuple(m_table, tuple);
    //cout << "Retrieved random tuple " << endl << tuple.debugNoHeader() << endl;

    size_t removed_bytes =
        StringRef::computeStringMemoryUsed(ValuePeeker::peekObjectLength(tuple.getNValue(1))) +
        StringRef::computeStringMemoryUsed(ValuePeeker::peekObjectLength(tuple.getNValue(2)));
    //cout << "Removing bytes from table: " << removed_bytes << endl;

    /*
     * A copy of the tuple to modify and use as a source tuple when
     * updating the new tuple.
     */
    TableTuple tempTuple = m_table->tempTuple();
    tempTuple.copy(tuple);
    string strval = "123456";
    NValue new_string = ValueFactory::getStringValue(strval);
    tempTuple.setNValue(1, new_string);
    //cout << "Created random tuple " << endl << tempTuple.debugNoHeader() << endl;
    size_t added_bytes =
        StringRef::computeStringMemoryUsed(ValuePeeker::peekObjectLength(tempTuple.getNValue(1))) +
        StringRef::computeStringMemoryUsed(ValuePeeker::peekObjectLength(tempTuple.getNValue(2)));
    //cout << "Adding bytes to table: " << added_bytes << endl;

    m_engine->setUndoToken(INT64_MIN + 2);
    // this next line is a testing hack until engine data is
    // de-duplicated with executorcontext data
    m_engine->getExecutorContext();

    m_table->updateTuple(tempTuple, tuple, true);

    ASSERT_EQ(orig_size + added_bytes - removed_bytes, m_table->nonInlinedMemorySize());

    m_engine->undoUndoToken(INT64_MIN + 2);

    ASSERT_EQ(orig_size, m_table->nonInlinedMemorySize());

    //tuple.freeObjectColumns();
    //tempTuple.freeObjectColumns();
    //delete [] tuple.address();
    //delete[] tempTuple.address();
    new_string.free();
}
bool MaterializedViewMetadata::findExistingTuple(TableTuple &oldTuple, bool expected) {
    // find the key for this tuple (which is the group by columns)
    for (int i = 0; i < m_groupByColumnCount; i++)
        m_searchKey.setNValue(i, oldTuple.getNValue(m_groupByColumns[i]));

    // determine if the row exists (create the empty one if it doesn't)
    m_index->moveToKey(&m_searchKey);
    m_existingTuple = m_index->nextValueAtKey();
    if (m_existingTuple.isNullTuple()) {
        if (expected) {
            throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION,
                                          "MaterializedViewMetadata went"
                                          " looking for a tuple in the view and"
                                          " expected to find it but didn't");
        }
        return false;
    }
    else {
        return true;
    }
}
bool MaterializedViewMetadata::findExistingTuple(TableTuple &oldTuple, bool expected) {
    // find the key for this tuple (which is the group by columns)
    for (int i = 0; i < m_groupByColumnCount; i++) {
        m_searchKey.setNValue(i, oldTuple.getNValue(m_groupByColumns[i]));
    }

    // determine if the row exists (create the empty one if it doesn't)
    m_index->moveToKey(&m_searchKey);
    m_existingTuple = m_index->nextValueAtKey();
    if (m_existingTuple.isNullTuple()) {
        if (expected) {
            std::string name = m_target->name();
            throwFatalException("MaterializedViewMetadata for table %s went"
                                " looking for a tuple in the view and"
                                " expected to find it but didn't", name.c_str());
        }
        return false;
    }
    else {
        return true;
    }
}
Beispiel #12
0
bool UpdateExecutor::p_execute(const NValueArray &params, ReadWriteTracker *tracker) {
    assert(m_inputTable);
    assert(m_targetTable);

    VOLT_TRACE("INPUT TABLE: %s\n", m_inputTable->debug().c_str());
    VOLT_TRACE("TARGET TABLE - BEFORE: %s\n", m_targetTable->debug().c_str());

    assert(m_inputTuple.sizeInValues() == m_inputTable->columnCount());
    assert(m_targetTuple.sizeInValues() == m_targetTable->columnCount());
    TableIterator input_iterator(m_inputTable);
    while (input_iterator.next(m_inputTuple)) {
        //
        // OPTIMIZATION: Single-Sited Query Plans
        // If our beloved UpdatePlanNode is apart of a single-site query plan,
        // then the first column in the input table will be the address of a
        // tuple on the target table that we will want to update. This saves us
        // the trouble of having to do an index lookup
        //
        void *target_address = m_inputTuple.getNValue(0).castAsAddress();
        m_targetTuple.move(target_address);
        
        // Read/Write Set Tracking
        if (tracker != NULL) {
            tracker->markTupleWritten(m_targetTable, &m_targetTuple);
        }

        // Loop through INPUT_COL_IDX->TARGET_COL_IDX mapping and only update
        // the values that we need to. The key thing to note here is that we
        // grab a temp tuple that is a copy of the target tuple (i.e., the tuple
        // we want to update). This insures that if the input tuple is somehow
        // bringing garbage with it, we're only going to copy what we really
        // need to into the target tuple.
        //
        TableTuple &tempTuple = m_targetTable->getTempTupleInlined(m_targetTuple);
        for (int map_ctr = 0; map_ctr < m_inputTargetMapSize; map_ctr++) {
            tempTuple.setNValue(m_inputTargetMap[map_ctr].second,
                                m_inputTuple.getNValue(m_inputTargetMap[map_ctr].first));
        }

        // if there is a partition column for the target table
        if (m_partitionColumn != -1) {
            // check for partition problems
            // get the value for the partition column
            NValue value = tempTuple.getNValue(m_partitionColumn);
            bool isLocal = m_engine->isLocalSite(value);

            // if it doesn't map to this site
            if (!isLocal) {
                VOLT_ERROR("Mispartitioned tuple in single-partition plan for"
                           " table '%s'", m_targetTable->name().c_str());
                return false;
            }
        }

        #ifdef ARIES
        if(m_engine->isARIESEnabled()){

            // add persistency check:
            PersistentTable* table = dynamic_cast<PersistentTable*>(m_targetTable);

            // only log if we are writing to a persistent table.
            if (table != NULL) {
                // before image -- target is old val with no updates
                // XXX: what about uninlined fields?
                // should we not be doing
                // m_targetTable->getTempTupleInlined(m_targetTuple); instead?
                TableTuple *beforeImage = &m_targetTuple;

                // after image -- temp is NEW, created using target and input
                TableTuple *afterImage = &tempTuple;

                TableTuple *keyTuple = NULL;
                char *keydata = NULL;
                std::vector<int32_t> modifiedCols;

                int32_t numCols = -1;

                // See if we can do better by using an index instead
                TableIndex *index = table->primaryKeyIndex();

                if (index != NULL) {
                    // First construct tuple for primary key
                    keydata = new char[index->getKeySchema()->tupleLength()];
                    keyTuple = new TableTuple(keydata, index->getKeySchema());

                    for (int i = 0; i < index->getKeySchema()->columnCount(); i++) {
                        keyTuple->setNValue(i, beforeImage->getNValue(index->getColumnIndices()[i]));
                    }

                    // no before image need be recorded, just the primary key
                    beforeImage = NULL;
                }

                // Set the modified column list
                numCols = m_inputTargetMapSize;

                modifiedCols.resize(m_inputTargetMapSize, -1);

                for (int map_ctr = 0; map_ctr < m_inputTargetMapSize; map_ctr++) {
                    // can't use column-id directly, otherwise we would go over vector bounds
                    int pos = m_inputTargetMap[map_ctr].first - 1;

                    modifiedCols.at(pos)
                    = m_inputTargetMap[map_ctr].second;
                }

                // Next, let the input tuple be the diff after image
                afterImage = &m_inputTuple;

                LogRecord *logrecord = new LogRecord(computeTimeStamp(),
                        LogRecord::T_UPDATE,// this is an update record
                        LogRecord::T_FORWARD,// the system is running normally
                        -1,// XXX: prevLSN must be fetched from table!
                        m_engine->getExecutorContext()->currentTxnId() ,// txn id
                        m_engine->getSiteId(),// which execution site
                        m_targetTable->name(),// the table affected
                        keyTuple,// primary key
                        numCols,
                        (numCols > 0) ? &modifiedCols : NULL,
                        beforeImage,
                        afterImage
                );

                size_t logrecordLength = logrecord->getEstimatedLength();
                char *logrecordBuffer = new char[logrecordLength];

                FallbackSerializeOutput output;
                output.initializeWithPosition(logrecordBuffer, logrecordLength, 0);

                logrecord->serializeTo(output);

                LogManager* m_logManager = this->m_engine->getLogManager();
                Logger m_ariesLogger = m_logManager->getAriesLogger();
                //VOLT_WARN("m_logManager : %p AriesLogger : %p",&m_logManager, &m_ariesLogger);
                const Logger *logger = m_logManager->getThreadLogger(LOGGERID_MM_ARIES);

                logger->log(LOGLEVEL_INFO, output.data(), output.position());

                delete[] logrecordBuffer;
                logrecordBuffer = NULL;

                delete logrecord;
                logrecord = NULL;

                if (keydata != NULL) {
                    delete[] keydata;
                    keydata = NULL;
                }

                if (keyTuple != NULL) {
                    delete keyTuple;
                    keyTuple = NULL;
                }
            }

        }
        #endif

        if (!m_targetTable->updateTuple(tempTuple, m_targetTuple,
                                        m_updatesIndexes)) {
            VOLT_INFO("Failed to update tuple from table '%s'",
                      m_targetTable->name().c_str());
            return false;
        }
    }

    VOLT_TRACE("TARGET TABLE - AFTER: %s\n", m_targetTable->debug().c_str());
    // TODO lets output result table here, not in result executor. same thing in
    // delete/insert

    // add to the planfragments count of modified tuples
    m_engine->m_tuplesModified += m_inputTable->activeTupleCount();

    return true;
}
 NValue compare(const TableTuple& tuple) const
 {
     assert(tuple.getSchema()->columnCount() == 1);
     return compare<OP>(tuple.getNValue(0));
 }
Beispiel #14
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;
}
Beispiel #15
0
void setSearchKeyFromTuple(TableTuple &source) {
    keyTuple.setNValue(0, source.getNValue(1));
    keyTuple.setNValue(1, source.getNValue(2));
}
Beispiel #16
0
bool DeleteExecutor::p_execute(const NValueArray &params, ReadWriteTracker *tracker) {
    assert(m_targetTable);

    if (m_truncate) {
        VOLT_TRACE("truncating table %s...", m_targetTable->name().c_str());
        // count the truncated tuples as deleted
        m_engine->m_tuplesModified += m_inputTable->activeTupleCount();

        #ifdef ARIES
        if(m_engine->isARIESEnabled()){
            // no need of persistency check, m_targetTable is
            // always persistent for deletes

            LogRecord *logrecord = new LogRecord(computeTimeStamp(),
                    LogRecord::T_TRUNCATE,// this is a truncate record
                    LogRecord::T_FORWARD,// the system is running normally
                    -1,// XXX: prevLSN must be fetched from table!
                    m_engine->getExecutorContext()->currentTxnId() ,// txn id
                    m_engine->getSiteId(),// which execution site
                    m_targetTable->name(),// the table affected
                    NULL,// primary key irrelevant
                    -1,// irrelevant numCols
                    NULL,// list of modified cols irrelevant
                    NULL,// before image irrelevant
                    NULL// after image irrelevant
            );

            size_t logrecordLength = logrecord->getEstimatedLength();
            char *logrecordBuffer = new char[logrecordLength];

            FallbackSerializeOutput output;
            output.initializeWithPosition(logrecordBuffer, logrecordLength, 0);

            logrecord->serializeTo(output);

            LogManager* m_logManager = this->m_engine->getLogManager();
            Logger m_ariesLogger = m_logManager->getAriesLogger();
            //VOLT_WARN("m_logManager : %p AriesLogger : %p",&m_logManager, &m_ariesLogger);
            const Logger *logger = m_logManager->getThreadLogger(LOGGERID_MM_ARIES);

            logger->log(LOGLEVEL_INFO, output.data(), output.position());

            delete[] logrecordBuffer;
            logrecordBuffer = NULL;

            delete logrecord;
            logrecord = NULL;

        }
        #endif

        //m_engine->context().incrementTuples(m_targetTable->activeTupleCount());
        // actually delete all the tuples
        m_targetTable->deleteAllTuples(true);
        return true;
    }
    // XXX : ARIES : Not sure if else is needed ?
    assert(m_inputTable);

    assert(m_inputTuple.sizeInValues() == m_inputTable->columnCount());
    assert(m_targetTuple.sizeInValues() == m_targetTable->columnCount());
    TableIterator inputIterator(m_inputTable);
    while (inputIterator.next(m_inputTuple)) {
        //
        // OPTIMIZATION: Single-Sited Query Plans
        // If our beloved DeletePlanNode is apart of a single-site query plan,
        // then the first column in the input table will be the address of a
        // tuple on the target table that we will want to blow away. This saves
        // us the trouble of having to do an index lookup
        //
        void *targetAddress = m_inputTuple.getNValue(0).castAsAddress();
        m_targetTuple.move(targetAddress);
        
        // Read/Write Set Tracking
        if (tracker != NULL) {
            tracker->markTupleWritten(m_targetTable, &m_targetTuple);
        }

        #ifdef ARIES
        if(m_engine->isARIESEnabled()){
            // no need of persistency check, m_targetTable is
            // always persistent for deletes

            // before image -- target is tuple to be deleted.
            TableTuple *beforeImage = &m_targetTuple;

            TableTuple *keyTuple = NULL;
            char *keydata = NULL;


            // See if we use an index instead
            TableIndex *index = m_targetTable->primaryKeyIndex();

            if (index != NULL) {
                // First construct tuple for primary key
                keydata = new char[index->getKeySchema()->tupleLength()];
                keyTuple = new TableTuple(keydata, index->getKeySchema());

                for (int i = 0; i < index->getKeySchema()->columnCount(); i++) {
                    keyTuple->setNValue(i, beforeImage->getNValue(index->getColumnIndices()[i]));
                }

                // no before image need be recorded, just the primary key
                beforeImage = NULL;
            }

            LogRecord *logrecord = new LogRecord(computeTimeStamp(),
                    LogRecord::T_DELETE,// this is a delete record
                    LogRecord::T_FORWARD,// the system is running normally
                    -1,// XXX: prevLSN must be fetched from table!
                    m_engine->getExecutorContext()->currentTxnId() ,// txn id
                    m_engine->getSiteId(),// which execution site
                    m_targetTable->name(),// the table affected
                    keyTuple,// primary key
                    -1,// must delete all columns
                    NULL,// no list of modified cols
                    beforeImage,
                    NULL// no after image
            );

            size_t logrecordLength = logrecord->getEstimatedLength();
            char *logrecordBuffer = new char[logrecordLength];

            FallbackSerializeOutput output;
            output.initializeWithPosition(logrecordBuffer, logrecordLength, 0);

            logrecord->serializeTo(output);

            LogManager* m_logManager = this->m_engine->getLogManager();
            Logger m_ariesLogger = m_logManager->getAriesLogger();
            //VOLT_WARN("m_logManager : %p AriesLogger : %p",&m_logManager, &m_ariesLogger);

            const Logger *logger = m_logManager->getThreadLogger(LOGGERID_MM_ARIES);

            logger->log(LOGLEVEL_INFO, output.data(), output.position());

            delete[] logrecordBuffer;
            logrecordBuffer = NULL;

            delete logrecord;
            logrecord = NULL;

            if (keydata != NULL) {
                delete[] keydata;
                keydata = NULL;
            }

            if (keyTuple != NULL) {
                delete keyTuple;
                keyTuple = NULL;
            }

        }
        #endif

        // Delete from target table
        if (!m_targetTable->deleteTuple(m_targetTuple, true)) {
            VOLT_ERROR("Failed to delete tuple from table '%s'",
                       m_targetTable->name().c_str());
            return false;
        }
    }

    // add to the planfragments count of modified tuples
    m_engine->m_tuplesModified += m_inputTable->activeTupleCount();
    //m_engine->context().incrementTuples(m_inputTable->activeTupleCount());

    return true;
}
Beispiel #17
0
/**
 * Generate hash value for key.
 */
ElasticHash ElasticIndex::generateHash(const PersistentTable &table, const TableTuple &tuple)
{
    return tuple.getNValue(table.partitionColumn()).murmurHash3();
}
    // Scan some records in the table, verifying that points that are
    // supposed to be inside are, and those that are not aren't.
    // Print out some stats about how long things took.
    void scanSomeRecords(PersistentTable *table, int numTuples, int numScans) {
        std::cout << "            Scanning for containing polygons on " << numScans << " points...\n";

        auto start = std::chrono::high_resolution_clock::now();
        std::chrono::microseconds usSpentScanning = std::chrono::duration_cast<microseconds>(start - start);
        std::chrono::microseconds usSpentContainsing = std::chrono::duration_cast<microseconds>(start - start);

        CoveringCellIndex* ccIndex = static_cast<CoveringCellIndex*>(table->index("poly_idx"));
        TableTuple tempTuple = table->tempTuple();
        StandAloneTupleStorage searchKey(ccIndex->getKeySchema());

        int numContainingCells = 0;
        int numContainingPolygons = 0;

        for (int i = 0; i < numScans; ++i) {
            // Pick a tuple at random.
            int pk = std::rand() % numTuples;
            tempTuple.setNValue(PK_COL_INDEX, ValueFactory::getIntegerValue(pk));
            TableTuple sampleTuple = table->lookupTupleByValues(tempTuple);
            ASSERT_FALSE(sampleTuple.isNullTuple());

            NValue geog = sampleTuple.getNValue(GEOG_COL_INDEX);
            if (geog.isNull()) {
                // There is one null row in the table.
                continue;
            }

            // The centroid will be inside polygons with one ring, and
            // not inside polygons with two rings (because the second
            // ring is a hole in the center).
            NValue centroid = geog.callUnary<FUNC_VOLT_POLYGON_CENTROID>();
            int32_t numInteriorRings = ValuePeeker::peekAsBigInt(geog.callUnary<FUNC_VOLT_POLYGON_NUM_INTERIOR_RINGS>());

            bool isValid = ValuePeeker::peekBoolean(geog.callUnary<FUNC_VOLT_VALIDATE_POLYGON>());
            if (! isValid) {
                std::ostringstream oss;
                int32_t len;
                const char* reasonChars = ValuePeeker::peekObject_withoutNull(geog.callUnary<FUNC_VOLT_POLYGON_INVALID_REASON>(), &len);
                std::string reason = std::string(reasonChars, len);
                oss << "At " << i << "th scan, expected a valid polygon at pk "
                    << pk << " but isValid says its not because \""
                    << reason << "\".  WKT:\n"
                    << nvalToWkt(geog);

                ASSERT_TRUE_WITH_MESSAGE(isValid, oss.str().c_str());
            }

            start = std::chrono::high_resolution_clock::now();

            searchKey.tuple().setNValue(0, centroid);
            IndexCursor cursor(ccIndex->getTupleSchema());

            bool foundSamplePoly = false;
            bool b = ccIndex->moveToCoveringCell(&searchKey.tuple(), cursor);
            if (b) {
                TableTuple foundTuple = ccIndex->nextValueAtKey(cursor);
                while (! foundTuple.isNullTuple()) {
                    ++numContainingCells;

                    auto startContains = std::chrono::high_resolution_clock::now();
                    bool polygonContains = ValuePeeker::peekBoolean(NValue::call<FUNC_VOLT_CONTAINS>({geog, centroid}));
                    auto endContains = std::chrono::high_resolution_clock::now();
                    usSpentContainsing += std::chrono::duration_cast<microseconds>(endContains - startContains);

                    if (polygonContains)
                        ++numContainingPolygons;

                    int foundPk = ValuePeeker::peekAsInteger(foundTuple.getNValue(PK_COL_INDEX));
                    if (foundPk == pk && polygonContains) {
                        foundSamplePoly = true;
                    }

                    foundTuple = ccIndex->nextValueAtKey(cursor);
                }
            }

            auto end = std::chrono::high_resolution_clock::now();
            usSpentScanning += std::chrono::duration_cast<microseconds>(end - start);

            ASSERT_TRUE(numInteriorRings == 0 || numInteriorRings == 1);

            if (numInteriorRings == 0 && !foundSamplePoly) {
                std::ostringstream oss;
                oss << "At " << i << "th scan, expected to find centroid in polygon with primary key "
                    << pk << ", centroid WKT:\n" << nvalToWkt(centroid)
                    << "\npolygon WKT:\n" << nvalToWkt(geog);
                ASSERT_TRUE_WITH_MESSAGE(foundSamplePoly, oss.str().c_str());
            }
            else if (numInteriorRings == 1) {
                // There was a hole in the center so the centroid is not in the polygon
                ASSERT_TRUE_WITH_MESSAGE(!foundSamplePoly, "Expected to not find centroid contained by polygon with hole in the center");
            }
        }

        auto avgTotalUsSpentScanning = usSpentScanning.count() / numScans;
        auto avgUsSpentContainsing = usSpentContainsing.count() / numScans;
        auto avgUsSpentScanning = avgTotalUsSpentScanning - avgUsSpentContainsing;
        std::cout << "              Average duration of each index lookup total: " << avgTotalUsSpentScanning << " us\n";
        std::cout << "                Average duration spent on CONTAINS: " << avgUsSpentContainsing << " us\n";
        std::cout << "                Average duration spent on B-tree traversal: " << avgUsSpentScanning << " us\n";

        double pctFalsePositives = (double(numContainingCells - numContainingPolygons) / numContainingCells) * 100.0;
        std::cout << "              Percent false positives (point in cell but not polygon): " << pctFalsePositives << "%\n";

        double avgCellsContainingPoint = numContainingCells / double(numScans);
        double avgPolygonsContainingPoint = numContainingPolygons / double(numScans);
        std::cout << "                On average, each point was in " << avgCellsContainingPoint << " cells\n";
        std::cout << "                On average, each point was in " << avgPolygonsContainingPoint << " polygons\n";
    }
Beispiel #19
0
bool InsertExecutor::p_execute(const NValueArray &params) {
    assert(m_node == dynamic_cast<InsertPlanNode*>(m_abstractNode));
    assert(m_node);
    assert(m_inputTable == dynamic_cast<TempTable*>(m_node->getInputTable()));
    assert(m_inputTable);

    // Target table can be StreamedTable or PersistentTable and must not be NULL
    // Update target table reference from table delegate
    Table* targetTable = m_node->getTargetTable();
    assert(targetTable);
    assert((targetTable == dynamic_cast<PersistentTable*>(targetTable)) ||
            (targetTable == dynamic_cast<StreamedTable*>(targetTable)));

    PersistentTable* persistentTable = m_isStreamed ?
        NULL : static_cast<PersistentTable*>(targetTable);
    TableTuple upsertTuple = TableTuple(targetTable->schema());

    VOLT_TRACE("INPUT TABLE: %s\n", m_inputTable->debug().c_str());

    // count the number of successful inserts
    int modifiedTuples = 0;

    Table* outputTable = m_node->getOutputTable();
    assert(outputTable);

    TableTuple templateTuple = m_templateTuple.tuple();

    std::vector<int>::iterator it;
    for (it = m_nowFields.begin(); it != m_nowFields.end(); ++it) {
        templateTuple.setNValue(*it, NValue::callConstant<FUNC_CURRENT_TIMESTAMP>());
    }

    VOLT_DEBUG("This is a %s-row insert on partition with id %d",
               m_node->getChildren()[0]->getPlanNodeType() == PLAN_NODE_TYPE_MATERIALIZE ?
               "single" : "multi", m_engine->getPartitionId());
    VOLT_DEBUG("Offset of partition column is %d", m_partitionColumn);

    //
    // An insert is quite simple really. We just loop through our m_inputTable
    // and insert any tuple that we find into our targetTable. It doesn't get any easier than that!
    //
    TableTuple inputTuple(m_inputTable->schema());
    assert (inputTuple.sizeInValues() == m_inputTable->columnCount());
    TableIterator iterator = m_inputTable->iterator();
    while (iterator.next(inputTuple)) {

        for (int i = 0; i < m_node->getFieldMap().size(); ++i) {
            // Most executors will just call setNValue instead of
            // setNValueAllocateForObjectCopies.
            //
            // However, We need to call
            // setNValueAlocateForObjectCopies here.  Sometimes the
            // input table's schema has an inlined string field, and
            // it's being assigned to the target table's outlined
            // string field.  In this case we need to tell the NValue
            // where to allocate the string data.
            templateTuple.setNValueAllocateForObjectCopies(m_node->getFieldMap()[i],
                                                           inputTuple.getNValue(i),
                                                           ExecutorContext::getTempStringPool());
        }

        VOLT_TRACE("Inserting tuple '%s' into target table '%s' with table schema: %s",
                   templateTuple.debug(targetTable->name()).c_str(), targetTable->name().c_str(),
                   targetTable->schema()->debug().c_str());

        // if there is a partition column for the target table
        if (m_partitionColumn != -1) {

            // get the value for the partition column
            NValue value = templateTuple.getNValue(m_partitionColumn);
            bool isLocal = m_engine->isLocalSite(value);

            // if it doesn't map to this site
            if (!isLocal) {
                if (!m_multiPartition) {
                    throw ConstraintFailureException(
                            dynamic_cast<PersistentTable*>(targetTable),
                            templateTuple,
                            "Mispartitioned tuple in single-partition insert statement.");
                }

                // don't insert
                continue;
            }
        }

        // for multi partition export tables, only insert into one
        // place (the partition with hash(0)), if the data is from a
        // replicated source.  If the data is coming from a subquery
        // with partitioned tables, we need to perform the insert on
        // every partition.
        if (m_isStreamed && m_multiPartition && !m_sourceIsPartitioned) {
            bool isLocal = m_engine->isLocalSite(ValueFactory::getBigIntValue(0));
            if (!isLocal) continue;
        }


        if (! m_isUpsert) {
            // try to put the tuple into the target table

            if (m_hasPurgeFragment) {
                if (!executePurgeFragmentIfNeeded(&persistentTable))
                    return false;
                // purge fragment might have truncated the table, and
                // refreshed the persistent table pointer.  Make sure to
                // use it when doing the insert below.
                targetTable = persistentTable;
            }

            if (!targetTable->insertTuple(templateTuple)) {
                VOLT_ERROR("Failed to insert tuple from input table '%s' into"
                           " target table '%s'",
                           m_inputTable->name().c_str(),
                           targetTable->name().c_str());
                return false;
            }

        } else {
            // upsert execution logic
            assert(persistentTable->primaryKeyIndex() != NULL);
            TableTuple existsTuple = persistentTable->lookupTupleByValues(templateTuple);

            if (existsTuple.isNullTuple()) {
                // try to put the tuple into the target table

                if (m_hasPurgeFragment) {
                    if (!executePurgeFragmentIfNeeded(&persistentTable))
                        return false;
                }

                if (!persistentTable->insertTuple(templateTuple)) {
                    VOLT_ERROR("Failed to insert tuple from input table '%s' into"
                               " target table '%s'",
                               m_inputTable->name().c_str(),
                               persistentTable->name().c_str());
                    return false;
                }
            } else {
                // tuple exists already, try to update the tuple instead
                upsertTuple.move(templateTuple.address());
                TableTuple &tempTuple = persistentTable->getTempTupleInlined(upsertTuple);

                if (!persistentTable->updateTupleWithSpecificIndexes(existsTuple, tempTuple,
                        persistentTable->allIndexes())) {
                    VOLT_INFO("Failed to update existsTuple from table '%s'",
                            persistentTable->name().c_str());
                    return false;
                }
            }
        }

        // successfully inserted or updated
        modifiedTuples++;
    }

    TableTuple& count_tuple = outputTable->tempTuple();
    count_tuple.setNValue(0, ValueFactory::getBigIntValue(modifiedTuples));
    // try to put the tuple into the output table
    if (!outputTable->insertTuple(count_tuple)) {
        VOLT_ERROR("Failed to insert tuple count (%d) into"
                   " output table '%s'",
                   modifiedTuples,
                   outputTable->name().c_str());
        return false;
    }

    // add to the planfragments count of modified tuples
    m_engine->addToTuplesModified(modifiedTuples);
    VOLT_DEBUG("Finished inserting %d tuples", modifiedTuples);
    return true;
}
Beispiel #20
0
int64_t TupleTrackerManager::getPrimaryKey(std::string tableName, uint32_t tupleId){

	Table* table = voltDBEngine->getTable(tableName);

	TableTuple tuple = TableTuple(table->schema());

	tuple.move(table->dataPtrForTuple(tupleId));

	TableIndex *m_index = table->primaryKeyIndex();

	std::vector<int> column_indices_vector = m_index->getColumnIndices();

	std::vector<int>::iterator it = column_indices_vector.begin();
	NValue colValue;

	int i = 0;

	while (it != column_indices_vector.end()) // this is for non composite key
	{
		colValue = tuple.getNValue(*it);
		it++;
		i++;
	}

	return colValue.castAsBigIntAndGetValue();
	//return i;
	//return colValue.isNull();

	/*

	it = std::find(column_indices_vector.begin(), column_indices_vector.end(), tupleId);

		return (int) std:: distance(column_indices_vector.begin(), it);


	TableTuple outputTuple = ... // tuple for your output table
   TableTuple inputTuple = ... // tuple from your tracking table
   TableTuple origTuple = ... // tuple from the original PersistantTable

    foreach (inputTuple in tracking table) {
    // (1) Get offset from inputTuple and move the origTuple to that location
    origTuple.move(table->dataPtrForTuple(tupleId));

    // (2) Now iterate over the pkey column offsets and copy the values into the inputTuple
    int col_idx = 0;
    for (pkey_offset in m_index->getColumnIndices()) {
        NValue colValue = origTuple.getNValue(pkey_offset);
        outputTuple.setNValue(col_idx, colValue);
        col_idx++;
    }

    // (3) Insert outputTuple into output table
     }



	int colCount = (int)column_indices_vector.size();



	if (colCount < tupleId)
		return -1;


	return column_indices_vector[tupleId];




   //*/
}
Beispiel #21
0
void InsertExecutor::p_execute_tuple_internal(TableTuple &tuple) {
    const std::vector<int>& fieldMap = m_node->getFieldMap();
    std::size_t mapSize = fieldMap.size();

    for (int i = 0; i < mapSize; ++i) {
        // Most executors will just call setNValue instead of
        // setNValueAllocateForObjectCopies.
        //
        // However, We need to call
        // setNValueAllocateForObjectCopies here.  Sometimes the
        // input table's schema has an inlined string field, and
        // it's being assigned to the target table's non-inlined
        // string field.  In this case we need to tell the NValue
        // where to allocate the string data.
        // For an "upsert", this templateTuple setup has two effects --
        // It sets the primary key column(s) and it sets the
        // updated columns to their new values.
        // If the primary key value (combination) is new, the
        // templateTuple is the exact combination of new values
        // and default values required by the insert.
        // If the primary key value (combination) already exists,
        // only the NEW values stored on the templateTuple get updated
        // in the existing tuple and its other columns keep their existing
        // values -- the DEFAULT values that are stored in templateTuple
        // DO NOT get copied to an existing tuple.
        m_templateTuple.setNValueAllocateForObjectCopies(fieldMap[i],
                                                         tuple.getNValue(i),
                                                         m_tempPool);
    }

    VOLT_TRACE("Inserting tuple '%s' into target table '%s' with table schema: %s",
               m_templateTuple.debug(m_targetTable->name()).c_str(), m_targetTable->name().c_str(),
               m_targetTable->schema()->debug().c_str());

    // If there is a partition column for the target table
    if (m_partitionColumn != -1) {
        // get the value for the partition column
        NValue value = m_templateTuple.getNValue(m_partitionColumn);
        bool isLocal = m_engine->isLocalSite(value);

        // if it doesn't map to this partiton
        if (!isLocal) {
            if (m_multiPartition) {
                // The same row is presumed to also be generated
                // on some other partition, where the partition key
                // belongs.
                return;
            }
            // When a streamed table has no views, let an SP insert execute.
            // This is backward compatible with when there were only export
            // tables with no views on them.
            // When there are views, be strict and throw mispartitioned
            // tuples to force partitioned data to be generated only
            // where partitioned view rows are maintained.
            if (!m_isStreamed || m_hasStreamView) {
                throw ConstraintFailureException(m_targetTable, m_templateTuple,
                                                 "Mispartitioned tuple in single-partition insert statement.");
            }
        }
    }

    if (m_isUpsert) {
        // upsert execution logic
        assert(m_persistentTable->primaryKeyIndex() != NULL);
        TableTuple existsTuple = m_persistentTable->lookupTupleByValues(m_templateTuple);

        if (!existsTuple.isNullTuple()) {
            // The tuple exists already, update (only) the templateTuple columns
            // that were initialized from the input tuple via the field map.
            // Technically, this includes setting primary key values,
            // but they are getting set to equivalent values, so that's OK.
            // A simple setNValue works here because any required object
            // allocations were handled when copying the input values into
            // the templateTuple.
            m_upsertTuple.move(m_templateTuple.address());
            TableTuple &tempTuple = m_persistentTable->copyIntoTempTuple(existsTuple);
            for (int i = 0; i < mapSize; ++i) {
                tempTuple.setNValue(fieldMap[i],
                                    m_templateTuple.getNValue(fieldMap[i]));
            }
            m_persistentTable->updateTupleWithSpecificIndexes(existsTuple, tempTuple,
                                                              m_persistentTable->allIndexes());
            // successfully updated
            ++m_modifiedTuples;
            return;
        }
        // else, the primary key did not match,
        // so fall through to the "insert" logic
    }

    // try to put the tuple into the target table
    if (m_hasPurgeFragment) {
        executePurgeFragmentIfNeeded(&m_persistentTable);
        // purge fragment might have truncated the table, and
        // refreshed the persistent table pointer.  Make sure to
        // use it when doing the insert below.
        m_targetTable = m_persistentTable;
    }
    m_targetTable->insertTuple(m_templateTuple);
    VOLT_TRACE("Target table:\n%s\n", m_targetTable->debug().c_str());
    // successfully inserted
    ++m_modifiedTuples;
    return;
}
void MaterializedViewMetadata::processTupleInsert(TableTuple &newTuple, bool fallible) {
    // don't change the view if this tuple doesn't match the predicate
    if (m_filterPredicate
        && (m_filterPredicate->eval(&newTuple, NULL).isFalse())) {
        return;
    }
    bool exists = findExistingTuple(newTuple);
    if (!exists) {
        // create a blank tuple
        m_existingTuple.move(m_emptyTupleBackingStore);
    }

    // clear the tuple that will be built to insert or overwrite
    memset(m_updatedTupleBackingStore, 0, m_target->schema()->tupleLength() + 1);

    int colindex = 0;
    // set up the first n columns, based on group-by columns
    for (colindex = 0; colindex < m_groupByColumnCount; colindex++) {
        // note that if the tuple is in the mv's target table,
        // tuple values should be pulled from the existing tuple in
        // that table. This works around a memory ownership issue
        // related to out-of-line strings.
        if (exists) {
            m_updatedTuple.setNValue(colindex,
                                 m_existingTuple.getNValue(colindex));
        }
        else {
            m_updatedTuple.setNValue(colindex,
                                 newTuple.getNValue(m_groupByColumns[colindex]));
        }
    }

    // set up the next column, which is a count
    m_updatedTuple.setNValue(colindex,
                             m_existingTuple.getNValue(colindex).op_increment());
    colindex++;

    // set values for the other columns
    for (int i = colindex; i < m_outputColumnCount; i++) {
        NValue newValue = newTuple.getNValue(m_outputColumnSrcTableIndexes[i]);
        NValue existingValue = m_existingTuple.getNValue(i);

        if (m_outputColumnAggTypes[i] == EXPRESSION_TYPE_AGGREGATE_SUM) {
            m_updatedTuple.setNValue(i, newValue.op_add(existingValue));
        }
        else if (m_outputColumnAggTypes[i] == EXPRESSION_TYPE_AGGREGATE_COUNT) {
            m_updatedTuple.setNValue(i, existingValue.op_increment());
        }
        else {
            char message[128];
            snprintf(message, 128, "Error in materialized view table update for"
                    " col %d. Expression type %d", i, m_outputColumnAggTypes[i]);
            throw SerializableEEException(VOLT_EE_EXCEPTION_TYPE_EEEXCEPTION,
                                          message);
        }
    }

    // update or insert the row
    if (exists) {
        // Shouldn't need to update group-key-only indexes such as the primary key
        // since their keys shouldn't ever change, but do update other indexes.
        m_target->updateTupleWithSpecificIndexes(m_existingTuple, m_updatedTuple,
                                                 m_updatableIndexList, fallible);
    }
    else {
        m_target->insertPersistentTuple(m_updatedTuple, fallible);
    }
}