common::Error SsdbDriver::commandCreateImpl(CommandCreateKey* command, std::string* cmdstring) const { if (!command || !cmdstring) { return common::make_error_value("Invalid input argument", common::ErrorValue::E_ERROR); } char patternResult[1024] = {0}; NDbKValue key = command->key(); NValue val = command->value(); common::Value* rval = val.get(); std::string key_str = key.keyString(); std::string value_str = common::convertToString(rval, " "); common::Value::Type t = key.type(); if (t == common::Value::TYPE_ARRAY) { common::SNPrintf(patternResult, sizeof(patternResult), SET_KEY_LIST_PATTERN_2ARGS_SS, key_str, value_str); } else if (t == common::Value::TYPE_SET) { common::SNPrintf(patternResult, sizeof(patternResult), SET_KEY_SET_PATTERN_2ARGS_SS, key_str, value_str); } else if (t == common::Value::TYPE_ZSET) { common::SNPrintf(patternResult, sizeof(patternResult), SET_KEY_ZSET_PATTERN_2ARGS_SS, key_str, value_str); } else if (t == common::Value::TYPE_HASH) { common::SNPrintf(patternResult, sizeof(patternResult), SET_KEY_HASH_PATTERN_2ARGS_SS, key_str, value_str); } else { common::SNPrintf(patternResult, sizeof(patternResult), SET_KEY_PATTERN_2ARGS_SS, key_str, value_str); } *cmdstring = patternResult; return common::Error(); }
TEST_F(TableTupleTest, HiddenColumns) { TupleSchemaBuilder builder(2, 2); builder.setColumnAtIndex(0, VALUE_TYPE_BIGINT); builder.setColumnAtIndex(1, VALUE_TYPE_VARCHAR, 256); builder.setHiddenColumnAtIndex(0, VALUE_TYPE_BIGINT); builder.setHiddenColumnAtIndex(1, VALUE_TYPE_VARCHAR, 10); ScopedTupleSchema schema(builder.build()); StandAloneTupleStorage autoStorage(schema.get()); const TableTuple& tuple = autoStorage.tuple(); NValue nvalVisibleBigint = ValueFactory::getBigIntValue(999); NValue nvalVisibleString = ValueFactory::getStringValue("catdog"); NValue nvalHiddenBigint = ValueFactory::getBigIntValue(1066); NValue nvalHiddenString = ValueFactory::getStringValue("platypus"); tuple.setNValue(0, nvalVisibleBigint); tuple.setNValue(1, nvalVisibleString); tuple.setHiddenNValue(0, nvalHiddenBigint); tuple.setHiddenNValue(1, nvalHiddenString); EXPECT_EQ(0, tuple.getNValue(0).compare(nvalVisibleBigint)); EXPECT_EQ(0, tuple.getNValue(1).compare(nvalVisibleString)); EXPECT_EQ(0, tuple.getHiddenNValue(0).compare(nvalHiddenBigint)); EXPECT_EQ(0, tuple.getHiddenNValue(1).compare(nvalHiddenString)); nvalVisibleString.free(); nvalHiddenString.free(); }
TEST_F(TableTupleTest, ComputeNonInlinedMemory) { UniqueEngine engine = UniqueEngineBuilder().build(); Pool *pool = ExecutorContext::getTempStringPool(); // Make sure that inlined strings are actually inlined int32_t maxInlinableLength = UNINLINEABLE_OBJECT_LENGTH/MAX_BYTES_PER_UTF8_CHARACTER - 1; ScopedTupleSchema allInlineSchema{Tools::buildSchema(VALUE_TYPE_BIGINT, std::make_pair(VALUE_TYPE_VARCHAR, maxInlinableLength))}; PoolBackedTupleStorage tupleStorage; tupleStorage.init(allInlineSchema.get(), pool); tupleStorage.allocateActiveTuple(); TableTuple inlineTuple = tupleStorage; Tools::setTupleValues(&inlineTuple, int64_t(0), "dude"); EXPECT_EQ(0, inlineTuple.getNonInlinedMemorySizeForPersistentTable()); // Now check that an non-inlined schema returns the right thing. int32_t nonInlinableLength = UNINLINEABLE_OBJECT_LENGTH + 10000; ScopedTupleSchema nonInlinedSchema{Tools::buildSchema(VALUE_TYPE_BIGINT, std::make_pair(VALUE_TYPE_VARCHAR, nonInlinableLength))}; tupleStorage.init(nonInlinedSchema.get(), pool); tupleStorage.allocateActiveTuple(); TableTuple nonInlinedTuple = tupleStorage; NValue nonInlinedString = Tools::nvalueFromNative("123456"); Tools::setTupleValues(&nonInlinedTuple, int64_t(0), nonInlinedString); EXPECT_EQ(nonInlinedString.getAllocationSizeForObjectInPersistentStorage(), nonInlinedTuple.getNonInlinedMemorySizeForPersistentTable()); }
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()); }
static std::string peekStringCopy(const NValue value) { assert((value.getValueType() == VALUE_TYPE_VARCHAR) || (value.getValueType() == VALUE_TYPE_VARBINARY)); std::string result(reinterpret_cast<const char*>(value.getObjectValue()), value.getObjectLength()); return result; }
NValue NValue::opDivideDecimals(const NValue lhs, const NValue rhs) const { if ((lhs.getValueType() != VALUE_TYPE_DECIMAL) || (rhs.getValueType() != VALUE_TYPE_DECIMAL)) { throw SQLException(SQLException::dynamic_sql_error, "No decimal NValue in decimal subtract"); } if (lhs.isNull() || rhs.isNull()) { TTInt retval; retval.SetMin(); return getDecimalValue( retval ); } TTLInt calc; calc.FromInt(lhs.getDecimal()); calc *= NValue::kMaxScaleFactor; if (calc.Div(rhs.getDecimal())) { char message[4096]; snprintf( message, 4096, "Attempted to divide %s by %s causing overflow/underflow (or divide by zero)", lhs.createStringFromDecimal().c_str(), rhs.createStringFromDecimal().c_str()); throw SQLException(SQLException::data_exception_numeric_value_out_of_range, message); } TTInt retval; if (retval.FromInt(calc) || retval > NValue::s_maxDecimal || retval < s_minDecimal) { char message[4096]; snprintf( message, 4096, "Attempted to divide %s by %s causing overflow. Unscaled result was %s", lhs.createStringFromDecimal().c_str(), rhs.createStringFromDecimal().c_str(), calc.ToString(10).c_str()); throw SQLException(SQLException::data_exception_numeric_value_out_of_range, message); } return getDecimalValue(retval); }
TableSerializeTest() { this->database_id = 1000; columnNames = new std::string[NUM_OF_COLUMNS]; std::vector<voltdb::ValueType> columnTypes; std::vector<int32_t> columnSizes; std::vector<bool> columnAllowNull(NUM_OF_COLUMNS, false); for (int ctr = 0; ctr < NUM_OF_COLUMNS; ctr++) { char name[16]; if (ctr == 0) ::snprintf(name, 16, "id"); else ::snprintf(name, 16, "val%02d", ctr); columnNames[ctr] = name; int size = (col_types[ctr] != VALUE_TYPE_VARCHAR ? 8 : 20); columnSizes.push_back(static_cast<int32_t>(size)); columnTypes.push_back(col_types[ctr]); } voltdb::TupleSchema *schema = voltdb::TupleSchema::createTupleSchema(columnTypes, columnSizes, columnAllowNull, true); table_ = TableFactory::getTempTable(this->database_id, "temp_table", schema, columnNames, NULL); for (int64_t i = 1; i <= TUPLES; ++i) { TableTuple &tuple = table_->tempTuple(); tuple.setNValue(0, ValueFactory::getTinyIntValue(static_cast<int8_t>(i))); tuple.setNValue(1, ValueFactory::getBigIntValue(static_cast<int16_t>(i % 2))); tuple.setNValue(2, ValueFactory::getBigIntValue(static_cast<int32_t>(i % 3))); tuple.setNValue(3, ValueFactory::getBigIntValue(static_cast<int64_t>(i % 5))); ostringstream str; str << "varchar string:" << (i % 7); NValue stringValue = ValueFactory::getStringValue(str.str()); tuple.setNValueAllocateForObjectCopies(4, stringValue, NULL); stringValue.free(); tuple.setNValue(5, ValueFactory::getDoubleValue(3.14f * static_cast<double>(i))); table_->insertTuple(tuple); } }
TEST_F(TableTupleTest, ToJsonArray) { TupleSchemaBuilder builder(3, 2); builder.setColumnAtIndex(0, VALUE_TYPE_BIGINT); builder.setColumnAtIndex(1, VALUE_TYPE_VARCHAR, 256); builder.setColumnAtIndex(2, VALUE_TYPE_VARCHAR, 256); builder.setHiddenColumnAtIndex(0, VALUE_TYPE_BIGINT); builder.setHiddenColumnAtIndex(1, VALUE_TYPE_VARCHAR, 10); ScopedTupleSchema schema(builder.build()); StandAloneTupleStorage autoStorage(schema.get()); const TableTuple& tuple = autoStorage.tuple(); NValue nvalVisibleBigint = ValueFactory::getBigIntValue(999); NValue nvalVisibleString = ValueFactory::getStringValue("数据库"); NValue nvalHiddenBigint = ValueFactory::getBigIntValue(1066); NValue nvalHiddenString = ValueFactory::getStringValue("platypus"); tuple.setNValue(0, nvalVisibleBigint); tuple.setNValue(1, nvalVisibleString); tuple.setNValue(2, ValueFactory::getNullValue()); tuple.setHiddenNValue(0, nvalHiddenBigint); tuple.setHiddenNValue(1, nvalHiddenString); EXPECT_EQ(0, strcmp(tuple.toJsonArray().c_str(), "[\"999\",\"数据库\",\"null\"]\n")); nvalHiddenString.free(); nvalVisibleString.free(); }
void NValue::castAndSortAndDedupArrayForInList(const ValueType outputType, std::vector<NValue> &outList) const { int size = arrayLength(); // make a set to eliminate unique values in O(nlogn) time std::set<StlFriendlyNValue> uniques; // iterate over the array of values and build a sorted set of unique // values that don't overflow or violate unique constaints // (n.b. sorted set means dups are removed) for (int i = 0; i < size; i++) { NValue value = itemAtIndex(i); // cast the value to the right type and catch overflow/cast problems try { StlFriendlyNValue stlValue; stlValue = value.castAs(outputType); std::pair<std::set<StlFriendlyNValue>::iterator, bool> ret; ret = uniques.insert(stlValue); } // cast exceptions mean the in-list test is redundant // don't include these values in the materialized table // TODO: make this less hacky catch (SQLException &sqlException) {} } // insert all items in the set in order std::set<StlFriendlyNValue>::const_iterator iter; for (iter = uniques.begin(); iter != uniques.end(); iter++) { outList.push_back(*iter); } }
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); } }
bool MaterializedScanExecutor::p_execute(const NValueArray ¶ms) { 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; }
bool CoveringCellIndex::getPolygonFromTuple(const TableTuple *tuple, Polygon *poly) const { NValue nval = tuple->getNValue(m_columnIndex); if (! nval.isNull()) { const GeographyValue gv = ValuePeeker::peekGeographyValue(nval); poly->initFromGeography(gv); return true; } return false; }
TEST_F(PersistentTableLogTest, InsertUpdateThenUndoOneTest) { initTable(); tableutil::addRandomTuples(m_table, 1); voltdb::TableTuple tuple(m_tableSchema); tableutil::getRandomTuple(m_table, tuple); //std::cout << "Retrieved random tuple " << std::endl << tuple.debugNoHeader() << std::endl; ASSERT_FALSE( m_table->lookupTupleForUndo(tuple).isNullTuple()); /* * A backup copy of what the tuple looked like before updates */ voltdb::TableTuple tupleBackup(m_tableSchema); tupleBackup.move(new char[tupleBackup.tupleLength()]); tupleBackup.copyForPersistentInsert(tuple); /* * A copy of the tuple to modify and use as a source tuple when updating the new tuple. */ voltdb::TableTuple tupleCopy(m_tableSchema); tupleCopy.move(new char[tupleCopy.tupleLength()]); tupleCopy.copyForPersistentInsert(tuple); m_engine->setUndoToken(INT64_MIN + 2); // this next line is a testing hack until engine data is // de-duplicated with executorcontext data m_engine->updateExecutorContextUndoQuantumForTest(); /* * Update a few columns */ tupleCopy.setNValue(0, ValueFactory::getBigIntValue(5)); NValue newStringValue = ValueFactory::getStringValue("foo"); tupleCopy.setNValue(7, newStringValue); NValue oldStringValue = tupleCopy.getNValue(6); tupleCopy.setNValue(6, ValueFactory::getStringValue("bar")); m_table->updateTuple(tuple, tupleCopy); ASSERT_TRUE( m_table->lookupTupleForUndo(tupleBackup).isNullTuple()); ASSERT_FALSE( m_table->lookupTupleForUndo(tupleCopy).isNullTuple()); m_engine->undoUndoToken(INT64_MIN + 2); ASSERT_FALSE(m_table->lookupTupleForUndo(tuple).isNullTuple()); ASSERT_TRUE( m_table->lookupTupleForUndo(tupleCopy).isNullTuple()); tupleBackup.freeObjectColumns(); tupleCopy.freeObjectColumns(); delete [] tupleBackup.address(); delete [] tupleCopy.address(); newStringValue.free(); oldStringValue.free(); }
NValue compare(const NValue& nvalue) const { assert(m_tuple.getSchema()->columnCount() == 1); NValue lvalue = m_tuple.getNValue(0); if (lvalue.isNull()) { return NValue::getNullValue(VALUE_TYPE_BOOLEAN); } if (nvalue.isNull()) { return NValue::getNullValue(VALUE_TYPE_BOOLEAN); } return OP::compare_withoutNull(lvalue, nvalue); }
extern "C" bool NValueLess(void* l, void* r) { /* * bool* ret_bool; * NValue* lnv = l; * NValue* rnv = r; * *ret_bool = lnv->op_less(rnv); * return ret_bool; */ NValue* lvalue = (NValue*) l; NValue* rvalue = (NValue*) r; return lvalue->op_less(*rvalue); }
virtual void advance(const NValue& val) { if (val.isNull()) { return; } if (!m_haveAdvanced) { m_value = val; if (m_value.getVolatile()) { // In serial aggregation, the NValue may be backed by // a row that is reused and updated for each row // produced by a child node. Because NValue's copy // constructor only does a shallow copy, this can lead // wrong answers when the Agg's NValue changes // unexpectedly. To avoid this, copy the // incoming NValue to its own storage. m_value.allocateObjectFromPool(m_memoryPool); m_inlineCopiedToNonInline = true; } m_haveAdvanced = true; } else { m_value = m_value.op_max(val); if (m_value.getVolatile()) { m_value.allocateObjectFromPool(m_memoryPool); } } }
virtual void advance(const NValue& val) { if (val.isNull()) { return; } if (!m_haveAdvanced) { m_value = val; if (m_value.getSourceInlined()) { // see comment in MaxAgg above, regarding why we're // doing this. m_value.allocateObjectFromInlinedValue(m_memoryPool); m_inlineCopiedToOutline = true; } m_haveAdvanced = true; } else { m_value = m_value.op_min(val); if (m_value.getSourceInlined()) { m_value.allocateObjectFromInlinedValue(m_memoryPool); } } }
virtual void advance(const NValue& val) { if (val.isNull() || ifDistinct.excludeValue(val)) { return; } m_count++; }
virtual void advance(const NValue& val) { if (val.isNull()) { return; } if (!m_haveAdvanced) { m_value = val; if (m_value.getSourceInlined()) { // If the incoming value is inlined, that means its // data really lives in a record somewhere. In serial // aggregation, the NValue may be backed by a row that // is reused and updated for each row produced by a // child node. Because NValue's copy constructor only // does a shallow copy, this can lead wrong answers // when the Agg's NValue changes unexpectedly. To // avoid this, un-inline the incoming NValue to its // own storage. m_value.allocateObjectFromInlinedValue(m_memoryPool); m_inlineCopiedToOutline = true; } m_haveAdvanced = true; } else { m_value = m_value.op_max(val); if (m_value.getSourceInlined()) { m_value.allocateObjectFromInlinedValue(m_memoryPool); } } }
TEST_F(DRBinaryLogTest, VerifyHiddenColumns) { ASSERT_FALSE(flush(98)); // single row write transaction beginTxn(99, 99, 98, 70); TableTuple first_tuple = insertTuple(m_table, prepareTempTuple(m_table, 42, 55555, "349508345.34583", "a thing", "a totally different thing altogether", 5433)); endTxn(true); flushAndApply(99); TableTuple tuple = m_tableReplica->lookupTupleByValues(first_tuple); NValue drTimestamp = tuple.getHiddenNValue(m_table->getDRTimestampColumnIndex()); NValue drTimestampReplica = tuple.getHiddenNValue(m_tableReplica->getDRTimestampColumnIndex()); EXPECT_EQ(ValuePeeker::peekAsBigInt(drTimestamp), 70); EXPECT_EQ(0, drTimestamp.compare(drTimestampReplica)); }
NValue compare(const NValue& nvalue) const { if (m_value.isNull() && OP::isNullRejecting()) { return NValue::getNullValue(VALUE_TYPE_BOOLEAN); } if (nvalue.isNull() && OP::isNullRejecting()) { return NValue::getNullValue(VALUE_TYPE_BOOLEAN); } return OP::compare(m_value, nvalue); }
NValue compare(const NValue& nvalue) const { if (m_value.isNull()) { return NValue::getNullValue(VALUE_TYPE_BOOLEAN); } if (nvalue.isNull()) { return NValue::getNullValue(VALUE_TYPE_BOOLEAN); } return OP::compare_withoutNull(m_value, nvalue); }
/** * This NValue can be of any scalar value type. * @param rhs a VALUE_TYPE_ARRAY NValue whose referent must be an NValueList. * The NValue elements of the NValueList should be comparable to and ideally * of exactly the same VALUE_TYPE as "this". * The planner and/or deserializer should have taken care of this with checks and * explicit cast operators and and/or constant promotions as needed. * @return a VALUE_TYPE_BOOLEAN NValue. */ bool NValue::inList(const NValue& rhs) const { //TODO: research: does the SQL standard allow a null to match a null list element // vs. returning FALSE or NULL? const bool lhsIsNull = isNull(); if (lhsIsNull) { return false; } const ValueType rhsType = rhs.getValueType(); if (rhsType != VALUE_TYPE_ARRAY) { throwDynamicSQLException("rhs of IN expression is of a non-list type %s", rhs.getValueTypeString().c_str()); } const NValueList* listOfNValues = (NValueList*)rhs.getObjectValue_withoutNull(); const StlFriendlyNValue& value = *static_cast<const StlFriendlyNValue*>(this); //TODO: An O(ln(length)) implementation vs. the current O(length) implementation // such as binary search would likely require some kind of sorting/re-org of values // post-update/pre-lookup, and would likely require some sortable inequality method // (operator<()?) to be defined on StlFriendlyNValue. return std::find(listOfNValues->begin(), listOfNValues->end(), value) != listOfNValues->end(); }
virtual void advance(const NValue& val) { if (val.isNull() || ifDistinct.excludeValue(val)) { return; } if (m_count == 0) { m_value = val; } else { m_value = m_value.op_add(val); } ++m_count; }
virtual void advance(const NValue& val) { if (val.isNull() || ifDistinct.excludeValue(val)) { return; } if (!m_haveAdvanced) { m_value = val; m_haveAdvanced = true; } else { m_value = m_value.op_add(val); } }
TEST_F(TableTupleTest, HiddenColumns) { UniqueEngine engine = UniqueEngineBuilder().build(); TupleSchemaBuilder builder(2, 2); builder.setColumnAtIndex(0, VALUE_TYPE_BIGINT); builder.setColumnAtIndex(1, VALUE_TYPE_VARCHAR, 256); builder.setHiddenColumnAtIndex(0, VALUE_TYPE_BIGINT); builder.setHiddenColumnAtIndex(1, VALUE_TYPE_VARCHAR, 10); ScopedTupleSchema schema(builder.build()); StandAloneTupleStorage autoStorage(schema.get()); TableTuple& tuple = autoStorage.tuple(); NValue nvalVisibleBigint = ValueFactory::getBigIntValue(999); NValue nvalVisibleString = ValueFactory::getStringValue("catdog"); NValue nvalHiddenBigint = ValueFactory::getBigIntValue(1066); NValue nvalHiddenString = ValueFactory::getStringValue("platypus"); tuple.setNValue(0, nvalVisibleBigint); tuple.setNValue(1, nvalVisibleString); tuple.setHiddenNValue(0, nvalHiddenBigint); tuple.setHiddenNValue(1, nvalHiddenString); EXPECT_EQ(0, tuple.getNValue(0).compare(nvalVisibleBigint)); EXPECT_EQ(0, tuple.getNValue(1).compare(nvalVisibleString)); EXPECT_EQ(0, tuple.getHiddenNValue(0).compare(nvalHiddenBigint)); EXPECT_EQ(0, tuple.getHiddenNValue(1).compare(nvalHiddenString)); EXPECT_EQ(8 + (4 + 6) + 8 + (4 + 8), tuple.maxDRSerializationSize()); tuple.setHiddenNValue(1, ValueFactory::getNullStringValue()); nvalHiddenString.free(); // The hidden string is null, takes 0 serialized byte EXPECT_EQ(8 + (4 + 6) + 8, tuple.maxDRSerializationSize()); nvalVisibleString.free(); }
TEST_F(PersistentTableLogTest, LookupTupleUsingTempTupleTest) { initNarrowTable(); // Create three tuple with a variable length VARCHAR column, then call // lookupTupleForUndo() to look each tuple up from wide to narrower column. // It will use the memcmp() code path for the comparison, which should all // succeed because there is no uninlined stuff. NValue wideStr = ValueFactory::getStringValue("a long string"); NValue narrowStr = ValueFactory::getStringValue("a"); NValue nullStr = ValueFactory::getNullStringValue(); TableTuple wideTuple(m_tableSchema); wideTuple.move(new char[wideTuple.tupleLength()]); ::memset(wideTuple.address(), 0, wideTuple.tupleLength()); wideTuple.setNValue(0, ValueFactory::getBigIntValue(1)); wideTuple.setNValue(1, wideStr); m_table->insertTuple(wideTuple); delete[] wideTuple.address(); TableTuple narrowTuple(m_tableSchema); narrowTuple.move(new char[narrowTuple.tupleLength()]); ::memset(narrowTuple.address(), 0, narrowTuple.tupleLength()); narrowTuple.setNValue(0, ValueFactory::getBigIntValue(2)); narrowTuple.setNValue(1, narrowStr); m_table->insertTuple(narrowTuple); delete[] narrowTuple.address(); TableTuple nullTuple(m_tableSchema); nullTuple.move(new char[nullTuple.tupleLength()]); ::memset(nullTuple.address(), 0, nullTuple.tupleLength()); nullTuple.setNValue(0, ValueFactory::getBigIntValue(3)); nullTuple.setNValue(1, nullStr); m_table->insertTuple(nullTuple); delete[] nullTuple.address(); TableTuple tempTuple = m_table->tempTuple(); tempTuple.setNValue(0, ValueFactory::getBigIntValue(1)); tempTuple.setNValue(1, wideStr); TableTuple result = m_table->lookupTupleForUndo(tempTuple); ASSERT_FALSE(result.isNullTuple()); tempTuple = m_table->tempTuple(); tempTuple.setNValue(0, ValueFactory::getBigIntValue(2)); tempTuple.setNValue(1, narrowStr); result = m_table->lookupTupleForUndo(tempTuple); ASSERT_FALSE(result.isNullTuple()); tempTuple = m_table->tempTuple(); tempTuple.setNValue(0, ValueFactory::getBigIntValue(3)); tempTuple.setNValue(1, nullStr); result = m_table->lookupTupleForUndo(tempTuple); ASSERT_FALSE(result.isNullTuple()); wideStr.free(); narrowStr.free(); nullStr.free(); }
void VCardFormatImpl::readNValue( ContentLine *cl, Addressee &a ) { NValue *v = (NValue *)cl->value(); a.setFamilyName( QString::fromUtf8( v->family() ) ); a.setGivenName( QString::fromUtf8( v->given() ) ); a.setAdditionalName( QString::fromUtf8( v->middle() ) ); a.setPrefix( QString::fromUtf8( v->prefix() ) ); a.setSuffix( QString::fromUtf8( v->suffix() ) ); }
virtual void advance(const NValue& val) { if (val.isNull()) { return; } if (!m_haveAdvanced) { m_value = val; m_haveAdvanced = true; } else { m_value = m_value.op_min(val); } }