This is an automated email from the ASF dual-hosted git repository. jackietien pushed a commit to branch new_object_type in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 1f5e9ece7319ab05c74d82ab6f748b2bb9d6bdd0 Author: Hongzhi Gao <[email protected]> AuthorDate: Tue Aug 5 16:42:05 2025 +0800 cpp client datatype OBJECT (#16094) * cpp client datatype OBJECT * removed unused notes --- iotdb-client/client-cpp/src/main/Common.cpp | 1 + iotdb-client/client-cpp/src/main/Common.h | 3 +- .../client-cpp/src/main/IoTDBRpcDataSet.cpp | 1 + iotdb-client/client-cpp/src/main/Session.cpp | 30 +++++++++--- iotdb-client/client-cpp/src/main/Session.h | 54 +++++++++++++++++++++- .../client-cpp/src/main/SessionDataSet.cpp | 2 + .../src/test/cpp/sessionRelationalIT.cpp | 12 ++++- 7 files changed, 92 insertions(+), 11 deletions(-) diff --git a/iotdb-client/client-cpp/src/main/Common.cpp b/iotdb-client/client-cpp/src/main/Common.cpp index cac4448b8e1..56dc9683057 100644 --- a/iotdb-client/client-cpp/src/main/Common.cpp +++ b/iotdb-client/client-cpp/src/main/Common.cpp @@ -89,6 +89,7 @@ TSDataType::TSDataType getDataTypeByStr(const std::string& typeStr) { if (typeStr == "DATE") return TSDataType::DATE; if (typeStr == "BLOB") return TSDataType::BLOB; if (typeStr == "STRING") return TSDataType::STRING; + if (typeStr == "OBJECT") return TSDataType::OBJECT; return TSDataType::UNKNOWN; } diff --git a/iotdb-client/client-cpp/src/main/Common.h b/iotdb-client/client-cpp/src/main/Common.h index 129e458c67b..aee44498605 100644 --- a/iotdb-client/client-cpp/src/main/Common.h +++ b/iotdb-client/client-cpp/src/main/Common.h @@ -95,7 +95,8 @@ enum TSDataType { TIMESTAMP = (char)8, DATE = (char)9, BLOB = (char)10, - STRING = (char)11 + STRING = (char)11, + OBJECT = (char)12 }; } diff --git a/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.cpp b/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.cpp index 7339d74c2c3..38bef0ab792 100644 --- a/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.cpp +++ b/iotdb-client/client-cpp/src/main/IoTDBRpcDataSet.cpp @@ -448,6 +448,7 @@ std::string IoTDBRpcDataSet::getStringByTsBlockColumnIndexAndDataType(int32_t in return std::to_string(curTsBlock_->getColumn(index)->getDouble(tsBlockIndex_)); case TSDataType::TEXT: case TSDataType::STRING: + case TSDataType::OBJECT: case TSDataType::BLOB: { auto binary = curTsBlock_->getColumn(index)->getBinary(tsBlockIndex_); return binary->getStringValue(); diff --git a/iotdb-client/client-cpp/src/main/Session.cpp b/iotdb-client/client-cpp/src/main/Session.cpp index 8182a67cccb..da1263527d1 100644 --- a/iotdb-client/client-cpp/src/main/Session.cpp +++ b/iotdb-client/client-cpp/src/main/Session.cpp @@ -59,6 +59,8 @@ TSDataType::TSDataType getTSDataTypeFromString(const string& str) { return TSDataType::BLOB; } else if (str == "STRING") { return TSDataType::STRING; + } else if (str == "OBJECT") { + return TSDataType::OBJECT; } return TSDataType::UNKNOWN; } @@ -88,6 +90,7 @@ void Tablet::createColumns() { break; case TSDataType::STRING: case TSDataType::BLOB: + case TSDataType::OBJECT: case TSDataType::TEXT: values[i] = new string[maxRowNumber]; break; @@ -135,6 +138,7 @@ void Tablet::deleteColumns() { } case TSDataType::STRING: case TSDataType::BLOB: + case TSDataType::OBJECT: case TSDataType::TEXT: { string* valueBuf = (string*)(values[i]); delete[] valueBuf; @@ -182,6 +186,7 @@ void Tablet::deepCopyTabletColValue(void* const* srcPtr, void** destPtr, TSDataT } case TSDataType::STRING: case TSDataType::TEXT: + case TSDataType::OBJECT: case TSDataType::BLOB: { *destPtr = new std::string[maxRowNumber]; std::string* srcStr = static_cast<std::string*>(src); @@ -232,6 +237,7 @@ size_t Tablet::getValueByteSize() { break; case TSDataType::STRING: case TSDataType::BLOB: + case TSDataType::OBJECT: case TSDataType::TEXT: { valueOccupation += rowSize * 4; string* valueBuf = (string*)(values[i]); @@ -361,6 +367,7 @@ string SessionUtils::getValue(const Tablet& tablet) { } case TSDataType::STRING: case TSDataType::BLOB: + case TSDataType::OBJECT: case TSDataType::TEXT: { string* valueBuf = (string*)(tablet.values[i]); for (size_t index = 0; index < tablet.rowSize; index++) { @@ -582,6 +589,7 @@ void Session::sortTablet(Tablet& tablet) { } case TSDataType::STRING: case TSDataType::BLOB: + case TSDataType::OBJECT: case TSDataType::TEXT: { sortValuesList((string*)(tablet.values[i]), index, tablet.rowSize); break; @@ -654,6 +662,7 @@ Session::putValuesIntoBuffer(const vector<TSDataType::TSDataType>& types, const break; case TSDataType::STRING: case TSDataType::BLOB: + case TSDataType::OBJECT: case TSDataType::TEXT: { int32_t len = (uint32_t)strlen(values[i]); appendValues(buf, (char*)(&len), sizeof(uint32_t)); @@ -689,6 +698,8 @@ int8_t Session::getDataTypeNumber(TSDataType::TSDataType type) { return 10; case TSDataType::STRING: return 11; + case TSDataType::OBJECT: + return 12; default: return -1; } @@ -1352,16 +1363,20 @@ void Session::buildInsertTabletReq(TSInsertTabletReq& request, Tablet& tablet, b sortTablet(tablet); } - request.prefixPath = tablet.deviceId; + request.__set_prefixPath(tablet.deviceId); - request.measurements.reserve(tablet.schemas.size()); - request.types.reserve(tablet.schemas.size()); + std::vector<std::string> reqMeasurements; + reqMeasurements.reserve(tablet.schemas.size()); + std::vector<int32_t> types; + types.reserve(tablet.schemas.size()); for (pair<string, TSDataType::TSDataType> schema : tablet.schemas) { - request.measurements.push_back(schema.first); - request.types.push_back(schema.second); + reqMeasurements.push_back(schema.first); + types.push_back(schema.second); } - request.values = move(SessionUtils::getValue(tablet)); - request.timestamps = move(SessionUtils::getTime(tablet)); + request.__set_measurements(reqMeasurements); + request.__set_types(types); + request.__set_values(SessionUtils::getValue(tablet)); + request.__set_timestamps(SessionUtils::getTime(tablet)); request.__set_size(tablet.rowSize); request.__set_isAligned(tablet.isAligned); } @@ -1446,6 +1461,7 @@ void Session::insertRelationalTablet(Tablet& tablet, bool sorted) { } case TSDataType::STRING: case TSDataType::TEXT: + case TSDataType::OBJECT: case TSDataType::BLOB: { currentTablet.addValue(tablet.schemas[col].first, rowIndex, *(string*)tablet.getValue(col, row, tablet.schemas[col].second)); diff --git a/iotdb-client/client-cpp/src/main/Session.h b/iotdb-client/client-cpp/src/main/Session.h index 35c05fad22c..4b901d5b20f 100644 --- a/iotdb-client/client-cpp/src/main/Session.h +++ b/iotdb-client/client-cpp/src/main/Session.h @@ -322,6 +322,58 @@ public: } } + // Add a Binary value with extra metadata: [isEOF (1 byte)] + [offset (8 bytes)] + [actual content] + void addValue(size_t schemaId, size_t rowIndex, bool isEOF, int64_t offset, const std::vector<uint8_t>& content) { + // Check schemaId bounds + if (schemaId >= schemas.size()) { + char tmpStr[100]; + sprintf(tmpStr, + "Tablet::addBinaryValueWithMeta(), schemaId >= schemas.size(). schemaId=%ld, schemas.size()=%ld.", + schemaId, schemas.size()); + throw std::out_of_range(tmpStr); + } + + // Check rowIndex bounds + if (rowIndex >= rowSize) { + char tmpStr[100]; + sprintf(tmpStr, "Tablet::addBinaryValueWithMeta(), rowIndex >= rowSize. rowIndex=%ld, rowSize=%ld.", + rowIndex, rowSize); + throw std::out_of_range(tmpStr); + } + + TSDataType::TSDataType dataType = schemas[schemaId].second; + if (dataType != TSDataType::OBJECT) { + throw std::invalid_argument("The data type of schemaId " + std::to_string(schemaId) + " is not OBJECT."); + } + + // Create a byte array of size [1 (isEOF) + 8 (offset) + content size] + std::vector<uint8_t> val(content.size() + 9); + + // Write the isEOF flag (1 byte) + val[0] = isEOF ? 1 : 0; + + // Write the 8-byte offset in big-endian order + for (int i = 0; i < 8; ++i) { + val[1 + i] = static_cast<uint8_t>((offset >> (56 - i * 8)) & 0xFF); + } + + // Append the content bytes + std::copy(content.begin(), content.end(), val.begin() + 9); + + // Cast the value array and assign the Binary data (stored as string) + std::string valEncoded = std::string(reinterpret_cast<char*>(val.data()), val.size()); + safe_cast<string, string>(valEncoded, ((string*)values[schemaId])[rowIndex]); + } + + void addValue(const string& schemaName, size_t rowIndex, bool isEOF, int64_t offset, + const std::vector<uint8_t>& content) { + if (schemaNameIndex.find(schemaName) == schemaNameIndex.end()) { + throw SchemaNotFoundException(string("Schema ") + schemaName + " not found."); + } + size_t schemaId = schemaNameIndex[schemaName]; + addValue(schemaId, rowIndex, isEOF, offset, content); + } + template <typename T> void addValue(const string& schemaName, size_t rowIndex, const T& value) { if (schemaNameIndex.find(schemaName) == schemaNameIndex.end()) { @@ -331,7 +383,6 @@ public: addValue(schemaId, rowIndex, value); } - void* getValue(size_t schemaId, size_t rowIndex, TSDataType::TSDataType dataType) { if (schemaId >= schemas.size()) { throw std::out_of_range("Tablet::getValue schemaId out of range: " @@ -358,6 +409,7 @@ public: return &(reinterpret_cast<double*>(values[schemaId])[rowIndex]); case TSDataType::BLOB: case TSDataType::STRING: + case TSDataType::OBJECT: case TSDataType::TEXT: return &(reinterpret_cast<std::string*>(values[schemaId])[rowIndex]); default: diff --git a/iotdb-client/client-cpp/src/main/SessionDataSet.cpp b/iotdb-client/client-cpp/src/main/SessionDataSet.cpp index 048d5340916..0cdd13402e4 100644 --- a/iotdb-client/client-cpp/src/main/SessionDataSet.cpp +++ b/iotdb-client/client-cpp/src/main/SessionDataSet.cpp @@ -98,6 +98,7 @@ std::string RowRecord::toString() { break; case TSDataType::BLOB: case TSDataType::STRING: + case TSDataType::OBJECT: case TSDataType::TEXT: if (!fields[i].stringV.is_initialized()) { ret.append("null"); @@ -268,6 +269,7 @@ shared_ptr<RowRecord> SessionDataSet::constructRowRecordFromValueArray() { case TSDataType::TEXT: case TSDataType::BLOB: case TSDataType::STRING: + case TSDataType::OBJECT: field.stringV = iotdbRpcDataSet_->getBinary(columnName)->getStringValue(); break; default: diff --git a/iotdb-client/client-cpp/src/test/cpp/sessionRelationalIT.cpp b/iotdb-client/client-cpp/src/test/cpp/sessionRelationalIT.cpp index 94f956b56ea..8dff31ba7f4 100644 --- a/iotdb-client/client-cpp/src/test/cpp/sessionRelationalIT.cpp +++ b/iotdb-client/client-cpp/src/test/cpp/sessionRelationalIT.cpp @@ -159,7 +159,8 @@ TEST_CASE("Test RelationalTabletTsblockRead", "[testRelationalTabletTsblockRead] "field7 TIMESTAMP field," "field8 DATE field," "field9 BLOB field," - "field10 STRING field)"); + "field10 STRING field," + "field11 OBJECT field)"); vector<pair<string, TSDataType::TSDataType>> schemaList; schemaList.push_back(make_pair("field1", TSDataType::BOOLEAN)); @@ -172,8 +173,9 @@ TEST_CASE("Test RelationalTabletTsblockRead", "[testRelationalTabletTsblockRead] schemaList.push_back(make_pair("field8", TSDataType::DATE)); schemaList.push_back(make_pair("field9", TSDataType::BLOB)); schemaList.push_back(make_pair("field10", TSDataType::STRING)); + schemaList.push_back(make_pair("field11", TSDataType::OBJECT)); - vector<ColumnCategory> columnTypes(10, ColumnCategory::FIELD); + vector<ColumnCategory> columnTypes(11, ColumnCategory::FIELD); int64_t timestamp = 0; int maxRowNumber = 50000; @@ -192,6 +194,9 @@ TEST_CASE("Test RelationalTabletTsblockRead", "[testRelationalTabletTsblockRead] tablet.addValue(7, rowIndex, boost::gregorian::date(2025, 5, 15)); tablet.addValue(8, rowIndex, "blob_" + to_string(row)); tablet.addValue(9, rowIndex, "string_" + to_string(row)); + vector<uint8_t> rawData = {0x01, 0x02, 0x03, 0x04}; + // always non-null + tablet.addValue(10, rowIndex, true, 0, rawData); if (row % 2 == 0) { for (int col = 0; col <= 9; col++) { @@ -227,6 +232,7 @@ TEST_CASE("Test RelationalTabletTsblockRead", "[testRelationalTabletTsblockRead] REQUIRE_FALSE(dataIter.getDateByIndex(9).is_initialized()); REQUIRE_FALSE(dataIter.getStringByIndex(10).is_initialized()); REQUIRE_FALSE(dataIter.getStringByIndex(11).is_initialized()); + REQUIRE_FALSE(!dataIter.getStringByIndex(12).is_initialized()); } else { REQUIRE(dataIter.getLongByIndex(1).value() == timestamp + rowNum); REQUIRE(dataIter.getBooleanByIndex(2).value() == (rowNum % 2 == 0)); @@ -239,6 +245,8 @@ TEST_CASE("Test RelationalTabletTsblockRead", "[testRelationalTabletTsblockRead] REQUIRE(dataIter.getDateByIndex(9).value() == boost::gregorian::date(2025, 5, 15)); REQUIRE(dataIter.getStringByIndex(10).value() == "blob_" + to_string(rowNum)); REQUIRE(dataIter.getStringByIndex(11).value() == "string_" + to_string(rowNum)); + // [isEOF (1 byte)] + [offset (8 bytes)] + [content (4 bytes)] + REQUIRE(dataIter.getStringByIndex(12).value() != ""); } rowNum++; }
