// helper to make a schema, a tuple and calculate EL size size_t TableTupleExportTest::maxElSize(std::vector<uint16_t> &keep_offsets, bool useNullStrings) { TableTuple *tt; TupleSchema *ts; char buf[1024]; // tuple data ts = TupleSchema::createTupleSchema(m_schema, keep_offsets); tt = new TableTuple(buf, ts); // if the tuple includes strings, add some content // assuming all Export tuples were allocated for persistent // storage and choosing set* api accordingly here. if (ts->columnCount() > 6) { NValue nv = ValueFactory::getStringValue("ABCDEabcde"); // 10 char if (useNullStrings) { nv.free(); nv.setNull(); } tt->setNValueAllocateForObjectCopies(6, nv, NULL); nv.free(); } if (ts->columnCount() > 7) { NValue nv = ValueFactory::getStringValue("abcdeabcdeabcdeabcde"); // 20 char if (useNullStrings) { nv.free(); nv.setNull(); } tt->setNValueAllocateForObjectCopies(7, nv, NULL); nv.free(); } // The function under test! size_t sz = tt->maxExportSerializationSize(); // and cleanup tt->freeObjectColumns(); delete tt; TupleSchema::freeTupleSchema(ts); return sz; }
bool InsertExecutor::p_execute(const NValueArray ¶ms) { 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; }
// helper to make a schema, a tuple and serialize to a buffer size_t TableTupleExportTest::serElSize(std::vector<uint16_t> &keep_offsets, uint8_t *nullArray, char *dataPtr, bool nulls) { TableTuple *tt; TupleSchema *ts; char buf[1024]; // tuple data ts = TupleSchema::createTupleSchema(m_schema, keep_offsets); tt = new TableTuple(buf, ts); // assuming all Export tuples were allocated for persistent // storage and choosing set* api accordingly here. switch (ts->columnCount()) { // note my sophisticated and clever use of fall through case 8: { NValue nv = ValueFactory::getStringValue("abcdeabcdeabcdeabcde"); // 20 char if (nulls) { nv.free(); nv.setNull(); } tt->setNValueAllocateForObjectCopies(7, nv, NULL); nv.free(); } case 7: { NValue nv = ValueFactory::getStringValue("ABCDEabcde"); // 10 char if (nulls) { nv.free(); nv.setNull(); } tt->setNValueAllocateForObjectCopies(6, nv, NULL); nv.free(); } case 6: { NValue nv = ValueFactory::getDecimalValueFromString("-12.34"); if (nulls) { nv.free(); nv.setNull(); } tt->setNValueAllocateForObjectCopies(5, nv, NULL); nv.free(); } case 5: { NValue nv = ValueFactory::getTimestampValue(9999); if (nulls) nv.setNull(); tt->setNValueAllocateForObjectCopies(4, nv, NULL); nv.free(); } case 4: { NValue nv = ValueFactory::getBigIntValue(1024); if (nulls) nv.setNull(); tt->setNValueAllocateForObjectCopies(3, nv, NULL); nv.free(); } case 3: { NValue nv = ValueFactory::getIntegerValue(512); if (nulls) nv.setNull(); tt->setNValueAllocateForObjectCopies(2, nv, NULL); nv.free(); } case 2: { NValue nv = ValueFactory::getSmallIntValue(256); if (nulls) nv.setNull(); tt->setNValueAllocateForObjectCopies(1, nv, NULL); nv.free(); } case 1: { NValue nv = ValueFactory::getTinyIntValue(120); if (nulls) nv.setNull(); tt->setNValueAllocateForObjectCopies(0, nv, NULL); nv.free(); } break; default: // this is an error in the test fixture. EXPECT_EQ(0,1); break; } // The function under test! ExportSerializeOutput io(dataPtr, 2048); tt->serializeToExport(io, 0, nullArray); // and cleanup tt->freeObjectColumns(); delete tt; TupleSchema::freeTupleSchema(ts); return io.position(); }