jt2594838 commented on code in PR #418: URL: https://github.com/apache/tsfile/pull/418#discussion_r1972733456
########## cpp/examples/README.md: ########## @@ -0,0 +1,77 @@ +<!-- + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + +--> + +# TsFile Reader/Writer Integration Guide + +## 1. Building TSFile Shared Library + +Build Methods (Choose either approach) + +### Method 1: Maven Build +Execute from the project root directory: + +```BASH +mvn package -P with-cpp clean verify +``` Review Comment: Add "If maven is not installed, may use 'mvnw.sh/bat' instead". ########## cpp/examples/c_examples/demo_read.c: ########## @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * License); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> + +#include "c_examples.h" + +// This example shows you how to read tsfile. +ERRNO read_tsfile() { + ERRNO code = 0; + char* table_name = "table1"; + + // Create tsfile reader with specify tsfile's path + TsFileReader reader = tsfile_reader_new("test_c.tsfile", &code); + HANDLE_ERROR(code); + + ResultSet ret = + tsfile_query_table(reader, table_name, (char*[]){"id1", "id2", "s1"}, 3, 0, 10, &code); + + // Get query result metadata: column name and datatype + ResultSetMetaData metadata = tsfile_result_set_get_metadata(ret); + int sensor_num = metadata.column_num; Review Comment: sensor is imprecise, just use column ########## cpp/examples/cpp_examples/demo_write.cpp: ########## @@ -27,88 +29,54 @@ using namespace storage; -long getNowTime() { return time(nullptr); } - -static std::string generate_random_string(int length) { - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<> dis(0, 61); - - const std::string chars = - "0123456789" - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - std::string random_string; - - for (int i = 0; i < length; ++i) { - random_string += chars[dis(gen)]; - } - - return random_string; -} - int demo_write() { - TsFileWriter* tsfile_writer_ = new TsFileWriter(); libtsfile_init(); - std::string file_name_ = std::string("tsfile_writer_test_") + - generate_random_string(10) + - std::string(".tsfile"); + std::string table_name = "table1"; + storage::WriteFile file; int flags = O_WRONLY | O_CREAT | O_TRUNC; #ifdef _WIN32 flags |= O_BINARY; #endif mode_t mode = 0666; - tsfile_writer_->open(file_name_, flags, mode); - remove(file_name_.c_str()); - const int device_num = 50; - const int measurement_num = 50; - std::vector<MeasurementSchema> schema_vec[50]; - for (int i = 0; i < device_num; i++) { - std::string device_name = "test_device" + std::to_string(i); - schema_vec[i].reserve(measurement_num); - for (int j = 0; j < measurement_num; j++) { - std::string measure_name = "measurement" + std::to_string(j); - schema_vec[i].emplace_back( - MeasurementSchema(measure_name, common::TSDataType::INT32, - common::TSEncoding::PLAIN, - common::CompressionType::UNCOMPRESSED)); - tsfile_writer_->register_timeseries(device_name, schema_vec[i][j]); - } - } + file.create("test_cpp.tsfile", flags, mode); + storage::TableSchema* schema = new storage::TableSchema( + table_name, + { + common::ColumnSchema("id1", common::STRING, common::UNCOMPRESSED, + common::PLAIN, common::ColumnCategory::TAG), + common::ColumnSchema("id2", common::STRING, common::UNCOMPRESSED, + common::PLAIN, common::ColumnCategory::TAG), + common::ColumnSchema("s1", common::INT64, common::UNCOMPRESSED, + common::PLAIN, common::ColumnCategory::FIELD), + }); - std::cout << "input tablet size" << std::endl; - int tablet_size; - std::cin >> tablet_size; + TsFileTableWriter* writer = new TsFileTableWriter(&file, schema); - int max_rows = 100000; - int cur_row = 0; - long start = getNowTime(); - for (; cur_row < max_rows;) { - if (cur_row + tablet_size > max_rows) { - tablet_size = max_rows - cur_row; - } - for (int i = 0; i < device_num; i++) { - std::string device_name = "test_device" + std::to_string(i); - Tablet tablet(device_name, &schema_vec[i], tablet_size); - tablet.init(); - for (int row = 0; row < tablet_size; row++) { - tablet.set_timestamp(row, 16225600 + cur_row + row); - } - for (int j = 0; j < measurement_num; j++) { - for (int row = 0; row < tablet_size; row++) { - tablet.set_value(row, j, row + cur_row); - } - } - tsfile_writer_->write_tablet(tablet); - tsfile_writer_->flush(); - } - cur_row += tablet_size; - std::cout << "finish writing " << cur_row << " rows" << std::endl; + storage::Tablet tablet = storage::Tablet( + table_name, {"id1", "id2", "s1"}, + {common::STRING, common::STRING, common::INT64}, + {common::ColumnCategory::TAG, common::ColumnCategory::TAG, + common::ColumnCategory::FIELD}, + 10); + char* literal = new char[std::strlen("id1_filed_1") + 1]; + std::strcpy(literal, "id1_filed_1"); Review Comment: Why not `char* literal = "id1_filed_1"`; ########## cpp/examples/cpp_examples/demo_write.cpp: ########## @@ -27,88 +29,54 @@ using namespace storage; -long getNowTime() { return time(nullptr); } - -static std::string generate_random_string(int length) { - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<> dis(0, 61); - - const std::string chars = - "0123456789" - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - std::string random_string; - - for (int i = 0; i < length; ++i) { - random_string += chars[dis(gen)]; - } - - return random_string; -} - int demo_write() { - TsFileWriter* tsfile_writer_ = new TsFileWriter(); libtsfile_init(); - std::string file_name_ = std::string("tsfile_writer_test_") + - generate_random_string(10) + - std::string(".tsfile"); + std::string table_name = "table1"; + storage::WriteFile file; int flags = O_WRONLY | O_CREAT | O_TRUNC; #ifdef _WIN32 flags |= O_BINARY; #endif mode_t mode = 0666; - tsfile_writer_->open(file_name_, flags, mode); - remove(file_name_.c_str()); - const int device_num = 50; - const int measurement_num = 50; - std::vector<MeasurementSchema> schema_vec[50]; - for (int i = 0; i < device_num; i++) { - std::string device_name = "test_device" + std::to_string(i); - schema_vec[i].reserve(measurement_num); - for (int j = 0; j < measurement_num; j++) { - std::string measure_name = "measurement" + std::to_string(j); - schema_vec[i].emplace_back( - MeasurementSchema(measure_name, common::TSDataType::INT32, - common::TSEncoding::PLAIN, - common::CompressionType::UNCOMPRESSED)); - tsfile_writer_->register_timeseries(device_name, schema_vec[i][j]); - } - } + file.create("test_cpp.tsfile", flags, mode); + storage::TableSchema* schema = new storage::TableSchema( + table_name, + { + common::ColumnSchema("id1", common::STRING, common::UNCOMPRESSED, + common::PLAIN, common::ColumnCategory::TAG), + common::ColumnSchema("id2", common::STRING, common::UNCOMPRESSED, + common::PLAIN, common::ColumnCategory::TAG), + common::ColumnSchema("s1", common::INT64, common::UNCOMPRESSED, + common::PLAIN, common::ColumnCategory::FIELD), + }); - std::cout << "input tablet size" << std::endl; - int tablet_size; - std::cin >> tablet_size; + TsFileTableWriter* writer = new TsFileTableWriter(&file, schema); - int max_rows = 100000; - int cur_row = 0; - long start = getNowTime(); - for (; cur_row < max_rows;) { - if (cur_row + tablet_size > max_rows) { - tablet_size = max_rows - cur_row; - } - for (int i = 0; i < device_num; i++) { - std::string device_name = "test_device" + std::to_string(i); - Tablet tablet(device_name, &schema_vec[i], tablet_size); - tablet.init(); - for (int row = 0; row < tablet_size; row++) { - tablet.set_timestamp(row, 16225600 + cur_row + row); - } - for (int j = 0; j < measurement_num; j++) { - for (int row = 0; row < tablet_size; row++) { - tablet.set_value(row, j, row + cur_row); - } - } - tsfile_writer_->write_tablet(tablet); - tsfile_writer_->flush(); - } - cur_row += tablet_size; - std::cout << "finish writing " << cur_row << " rows" << std::endl; + storage::Tablet tablet = storage::Tablet( + table_name, {"id1", "id2", "s1"}, + {common::STRING, common::STRING, common::INT64}, + {common::ColumnCategory::TAG, common::ColumnCategory::TAG, + common::ColumnCategory::FIELD}, + 10); + char* literal = new char[std::strlen("id1_filed_1") + 1]; + std::strcpy(literal, "id1_filed_1"); + common::String literal_str(literal, std::strlen("id1_filed_1")); + char* literal2 = new char[std::strlen("id1_filed_2") + 1]; + std::strcpy(literal, "id1_filed_2"); + common::String literal_str2(literal2, std::strlen("id1_filed_2")); + for (int row = 0; row < 5; row++) { + long timestamp = row; + tablet.add_timestamp(row, timestamp); + tablet.add_value(row, "id1", literal_str); + tablet.add_value(row, "id2", literal_str2); + tablet.add_value(row, "s1", static_cast<int64_t>(row)); } - - tsfile_writer_->close(); - long end = getNowTime(); - printf("interval waitForResults is %ld \n", end - start); + writer->write_table(tablet); Review Comment: Handle error ########## cpp/src/writer/tsfile_writer.cc: ########## @@ -688,6 +710,10 @@ int TsFileWriter::write_table(Tablet &tablet) { ret = E_DEVICE_NOT_EXIST; Review Comment: E_TABLE_NOT_EXIST ########## cpp/examples/c_examples/demo_write.c: ########## @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * License); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <malloc.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include "c_examples.h" + +ERRNO write_tsfile() { + ERRNO code = 0; + char* table_name = "table1"; + TableSchema table_schema = { + .table_name = table_name, + .column_schemas = + (ColumnSchema[]){(ColumnSchema){.column_name = "id1", + .data_type = TS_DATATYPE_STRING, + .column_category = TAG}, + (ColumnSchema){.column_name = "id2", + .data_type = TS_DATATYPE_STRING, + .column_category = TAG}, + (ColumnSchema){.column_name = "s1", + .data_type = TS_DATATYPE_INT32, + .column_category = FIELD}}}; + WriteFile file = write_file_new("test_c.tsfile", &code); + HANDLE_ERROR(code); + + // Create tsfile writer with specify path. + TsFileWriter writer = tsfile_writer_new(file, &table_schema, &code); + HANDLE_ERROR(code); + + // Create tablet to insert data. + Tablet tablet = + tablet_new((char*[]){"id1", "id2", "s1"}, + (TSDataType[]){TS_DATATYPE_STRING, TS_DATATYPE_STRING, + TS_DATATYPE_INT32}, + 3, 5); + + for (int row = 0; row < 5; row++) { + Timestamp timestamp = row; + tablet_add_timestamp(tablet, row, timestamp); + tablet_add_value_by_name_string(tablet, row, "id1", "id_field_1"); + tablet_add_value_by_name_string(tablet, row, "id2", "id_field_2"); + tablet_add_value_by_name_int32_t(tablet, row, "s1", row); + } + + // Write tablet data. + HANDLE_ERROR(tsfile_writer_write(writer, tablet)); + + // Close writer. + HANDLE_ERROR(tsfile_writer_close(writer)); +} Review Comment: Free tablet. Is file (WriteFile) freed by tsfile_writer_close? ########## cpp/examples/c_examples/demo_read.c: ########## @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * License); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> + +#include "c_examples.h" + +// This example shows you how to read tsfile. +ERRNO read_tsfile() { + ERRNO code = 0; + char* table_name = "table1"; + + // Create tsfile reader with specify tsfile's path + TsFileReader reader = tsfile_reader_new("test_c.tsfile", &code); + HANDLE_ERROR(code); + + ResultSet ret = + tsfile_query_table(reader, table_name, (char*[]){"id1", "id2", "s1"}, 3, 0, 10, &code); + + // Get query result metadata: column name and datatype + ResultSetMetaData metadata = tsfile_result_set_get_metadata(ret); + int sensor_num = metadata.column_num; + + for (int i = 0; i < sensor_num; i++) { + printf("column:%s, datatype:%d\n", metadata.column_names[i], + metadata.data_types[i]); + } + + // Get data by column name or index. + while (tsfile_result_set_next(ret, &code) && code == RET_OK) { + Timestamp timestamp = tsfile_result_set_get_value_by_index_int64_t(ret, 1); + printf("%ld ", timestamp); + for (int i = 1; i < sensor_num; i++) { + if (tsfile_result_set_is_null_by_index(ret, i)) { + printf("null "); + } else { + switch (metadata.data_types[i]) { + case TS_DATATYPE_BOOLEAN: + printf("%d", tsfile_result_set_get_value_by_index_bool(ret, i)); + break; + case TS_DATATYPE_INT32: + printf("%d", tsfile_result_set_get_value_by_index_int32_t(ret, i)); + break; + case TS_DATATYPE_INT64: + // 注意:int64_t 应使用 %lld(Linux)或 %I64d(Windows) Review Comment: Do not mix CHN with ENG ########## cpp/examples/cpp_examples/demo_read.cpp: ########## @@ -20,78 +20,63 @@ #include <string> #include <vector> +#include "../c_examples/c_examples.h" #include "cpp_examples.h" -std::string field_to_string(storage::Field *value) { - if (value->type_ == common::TEXT) { - return std::string(value->value_.sval_); - } else { - std::stringstream ss; - switch (value->type_) { - case common::BOOLEAN: - ss << (value->value_.bval_ ? "true" : "false"); - break; - case common::INT32: - ss << value->value_.ival_; - break; - case common::INT64: - ss << value->value_.lval_; - break; - case common::FLOAT: - ss << value->value_.fval_; - break; - case common::DOUBLE: - ss << value->value_.dval_; - break; - case common::NULL_TYPE: - ss << "NULL"; - break; - default: - ASSERT(false); - break; - } - return ss.str(); - } -} - +using namespace storage; int demo_read() { - std::cout << "begin to read tsfile from demo_ts.tsfile" << std::endl; - std::string device_name = "root.db001.dev001"; - std::string measurement_name = "m001"; - storage::Path p1(device_name, measurement_name); - std::vector<storage::Path> select_list; - select_list.push_back(p1); - storage::QueryExpression *query_expr = - storage::QueryExpression::create(select_list, nullptr); - - common::init_config_value(); + ERRNO code = 0; + libtsfile_init(); + std::string table_name = "table1"; storage::TsFileReader reader; - int ret = reader.open("cpp_rw.tsfile"); - - std::cout << "begin to query expr" << std::endl; - ASSERT(ret == 0); - storage::ResultSet *qds = nullptr; - ret = reader.query(query_expr, qds); - - storage::RowRecord *record; - std::cout << "begin to dump data from tsfile ---" << std::endl; - int row_cout = 0; - do { - if (qds->next()) { - std::cout << "dump QDS : " << record->get_timestamp() << ","; - record = qds->get_row_record(); - if (record) { - int size = record->get_fields()->size(); - for (int i = 0; i < size; ++i) { - std::cout << field_to_string(record->get_field(i)) << ","; + reader.open("test_cpp.tsfile"); + storage::ResultSet* temp_ret = nullptr; + std::vector<std::string> columns; + columns.emplace_back("id1"); + columns.emplace_back("id2"); + columns.emplace_back("s1"); + code = reader.query(table_name, columns, 0, 100, temp_ret); Review Comment: Check code ########## cpp/examples/cpp_examples/demo_read.cpp: ########## @@ -20,78 +20,63 @@ #include <string> #include <vector> +#include "../c_examples/c_examples.h" #include "cpp_examples.h" -std::string field_to_string(storage::Field *value) { - if (value->type_ == common::TEXT) { - return std::string(value->value_.sval_); - } else { - std::stringstream ss; - switch (value->type_) { - case common::BOOLEAN: - ss << (value->value_.bval_ ? "true" : "false"); - break; - case common::INT32: - ss << value->value_.ival_; - break; - case common::INT64: - ss << value->value_.lval_; - break; - case common::FLOAT: - ss << value->value_.fval_; - break; - case common::DOUBLE: - ss << value->value_.dval_; - break; - case common::NULL_TYPE: - ss << "NULL"; - break; - default: - ASSERT(false); - break; - } - return ss.str(); - } -} - +using namespace storage; int demo_read() { - std::cout << "begin to read tsfile from demo_ts.tsfile" << std::endl; - std::string device_name = "root.db001.dev001"; - std::string measurement_name = "m001"; - storage::Path p1(device_name, measurement_name); - std::vector<storage::Path> select_list; - select_list.push_back(p1); - storage::QueryExpression *query_expr = - storage::QueryExpression::create(select_list, nullptr); - - common::init_config_value(); + ERRNO code = 0; + libtsfile_init(); + std::string table_name = "table1"; storage::TsFileReader reader; - int ret = reader.open("cpp_rw.tsfile"); - - std::cout << "begin to query expr" << std::endl; - ASSERT(ret == 0); - storage::ResultSet *qds = nullptr; - ret = reader.query(query_expr, qds); - - storage::RowRecord *record; - std::cout << "begin to dump data from tsfile ---" << std::endl; - int row_cout = 0; - do { - if (qds->next()) { - std::cout << "dump QDS : " << record->get_timestamp() << ","; - record = qds->get_row_record(); - if (record) { - int size = record->get_fields()->size(); - for (int i = 0; i < size; ++i) { - std::cout << field_to_string(record->get_field(i)) << ","; + reader.open("test_cpp.tsfile"); + storage::ResultSet* temp_ret = nullptr; + std::vector<std::string> columns; + columns.emplace_back("id1"); + columns.emplace_back("id2"); + columns.emplace_back("s1"); + code = reader.query(table_name, columns, 0, 100, temp_ret); + auto ret = static_cast<storage::TableResultSet*>(temp_ret); + auto metadata = ret->get_metadata(); + int column_num = metadata->get_column_count(); + for (int i = 0; i < column_num; i++) { + std::cout << "column name: " << metadata->get_column_name(i) + << std::endl; + std::cout << "column type: " << metadata->get_column_type(i) + << std::endl; + } + bool has_next = false; + while (ret->next(has_next) == common::E_OK && has_next) { Review Comment: Store the code in a variable. Otherwise, if an error occurs, the user will not be able to know what it is. ########## cpp/examples/c_examples/demo_read.c: ########## @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * License); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> + +#include "c_examples.h" + +// This example shows you how to read tsfile. +ERRNO read_tsfile() { + ERRNO code = 0; + char* table_name = "table1"; + + // Create tsfile reader with specify tsfile's path + TsFileReader reader = tsfile_reader_new("test_c.tsfile", &code); + HANDLE_ERROR(code); + + ResultSet ret = + tsfile_query_table(reader, table_name, (char*[]){"id1", "id2", "s1"}, 3, 0, 10, &code); Review Comment: HANDLE_ERROR(code) ########## cpp/src/cwrapper/tsfile_cwrapper.cc: ########## @@ -314,22 +381,40 @@ TSFILE_RESULT_SET_GET_VALUE_BY_INDEX_DEF(float); TSFILE_RESULT_SET_GET_VALUE_BY_INDEX_DEF(double); TSFILE_RESULT_SET_GET_VALUE_BY_INDEX_DEF(bool); +char *tsfile_result_set_get_value_by_index_string(ResultSet result_set, + uint32_t column_index) { + auto *r = static_cast<storage::TableResultSet *>(result_set); + common::String *ret = r->get_value<common::String *>(column_index); + // Caller should free return's char* 's space. + char* dup = (char*) malloc(ret->len_ + 1); + if (dup) { + memcpy(dup, ret->buf_, ret->len_); + dup[ret->len_] = '\0'; + } + return dup; +} + bool tsfile_result_set_is_null_by_name(ResultSet result_set, const char *column_name) { - auto *r = static_cast<storage::ResultSet *>(result_set); + auto *r = static_cast<storage::TableResultSet *>(result_set); return r->is_null(column_name); } bool tsfile_result_set_is_null_by_index(const ResultSet result_set, const uint32_t column_index) { - auto *r = static_cast<storage::ResultSet *>(result_set); + auto *r = static_cast<storage::TableResultSet *>(result_set); return r->is_null(column_index); } ResultSetMetaData tsfile_result_set_get_metadata(ResultSet result_set) { - auto *r = static_cast<storage::QDSWithoutTimeGenerator *>(result_set); + auto *r = static_cast<storage::TableResultSet *>(result_set); + if (result_set == NULL) { + return ResultSetMetaData(); + } Review Comment: Maybe return null is better. ########## cpp/src/cwrapper/tsfile_cwrapper.cc: ########## @@ -344,73 +429,106 @@ ResultSetMetaData tsfile_result_set_get_metadata(ResultSet result_set) { return meta_data; } -char *tsfile_result_set_meta_get_column_name(ResultSetMetaData result_set, - uint32_t column_index) { +char *tsfile_result_set_metadata_get_column_name(ResultSetMetaData result_set, + uint32_t column_index) { + if (column_index >= result_set.column_num) { + return nullptr; + } return result_set.column_names[column_index]; } -TSDataType tsfile_result_set_meta_get_data_type(ResultSetMetaData result_set, - uint32_t column_index) { +TSDataType tsfile_result_set_metadata_get_data_type( + ResultSetMetaData result_set, uint32_t column_index) { + if (column_index < 0 || column_index >= result_set.column_num) { + return TS_DATATYPE_INVALID; + } Review Comment: return INDEX_OUT_OF_BOUND ########## cpp/examples/c_examples/demo_read.c: ########## @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * License); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> + +#include "c_examples.h" + +// This example shows you how to read tsfile. +ERRNO read_tsfile() { + ERRNO code = 0; + char* table_name = "table1"; + + // Create tsfile reader with specify tsfile's path + TsFileReader reader = tsfile_reader_new("test_c.tsfile", &code); + HANDLE_ERROR(code); + + ResultSet ret = + tsfile_query_table(reader, table_name, (char*[]){"id1", "id2", "s1"}, 3, 0, 10, &code); + + // Get query result metadata: column name and datatype + ResultSetMetaData metadata = tsfile_result_set_get_metadata(ret); + int sensor_num = metadata.column_num; + + for (int i = 0; i < sensor_num; i++) { + printf("column:%s, datatype:%d\n", metadata.column_names[i], + metadata.data_types[i]); + } + + // Get data by column name or index. + while (tsfile_result_set_next(ret, &code) && code == RET_OK) { + Timestamp timestamp = tsfile_result_set_get_value_by_index_int64_t(ret, 1); + printf("%ld ", timestamp); + for (int i = 1; i < sensor_num; i++) { + if (tsfile_result_set_is_null_by_index(ret, i)) { + printf("null "); + } else { + switch (metadata.data_types[i]) { + case TS_DATATYPE_BOOLEAN: + printf("%d", tsfile_result_set_get_value_by_index_bool(ret, i)); + break; + case TS_DATATYPE_INT32: + printf("%d", tsfile_result_set_get_value_by_index_int32_t(ret, i)); + break; + case TS_DATATYPE_INT64: + // 注意:int64_t 应使用 %lld(Linux)或 %I64d(Windows) + printf("%lld", tsfile_result_set_get_value_by_index_int64_t(ret, i)); + break; + case TS_DATATYPE_FLOAT: + printf("%f", tsfile_result_set_get_value_by_index_float(ret, i)); + break; + case TS_DATATYPE_DOUBLE: + printf("%lf", tsfile_result_set_get_value_by_index_double(ret, i)); + break; + case TS_DATATYPE_STRING: + printf("%s", tsfile_result_set_get_value_by_index_string(ret, i)); + break; + default: + printf("unknown_type"); + break; + } + } + } + } + + free_result_set_meta_data(metadata); + free_tsfile_result_set(ret); + return 0; Review Comment: free TsFileReader ########## cpp/src/cwrapper/tsfile_cwrapper.h: ########## @@ -109,94 +118,246 @@ typedef void* TsRecord; typedef void* ResultSet; typedef int32_t ERRNO; -typedef int64_t timestamp; +typedef int64_t Timestamp; -#ifdef __cplusplus -extern "C" { -#endif +/*--------------------------TsFile Reader and Writer------------------------ */ + +/** + * @brief Creates a file for writing. + * + * @param pathname Target file path to create. + * @param err_code [out] E_OK(0), or check error code in errno_define.h. + * + * @return WriteFile Valid handle on success. + * + * @note Call free_write_file() to release resources. + */ + +WriteFile write_file_new(const char* pathname, ERRNO* err_code); + +/** + * @brief Creates a TsFileWriter for writing TsFiles. + * + * @param file Target file where the table data will be written. + * @param schema Table schema definition. + * - Ownership: Caller must free it after writer creating. + * @param err_code [out] E_OK(0), or check error code in errno_define.h. + * + * @return TsFileWriter Valid handle on success, NULL on failure. + * + * @note Call tsfile_writer_close() to release resources. + */ +TsFileWriter tsfile_writer_new(WriteFile file, TableSchema* schema, + ERRNO* err_code); + +/** + * @brief Creates a TsFileReader for reading TsFiles. Review Comment: a TsFile ########## cpp/src/cwrapper/tsfile_cwrapper.h: ########## @@ -109,94 +118,246 @@ typedef void* TsRecord; typedef void* ResultSet; typedef int32_t ERRNO; -typedef int64_t timestamp; +typedef int64_t Timestamp; -#ifdef __cplusplus -extern "C" { -#endif +/*--------------------------TsFile Reader and Writer------------------------ */ + +/** + * @brief Creates a file for writing. + * + * @param pathname Target file path to create. + * @param err_code [out] E_OK(0), or check error code in errno_define.h. + * + * @return WriteFile Valid handle on success. + * + * @note Call free_write_file() to release resources. + */ + +WriteFile write_file_new(const char* pathname, ERRNO* err_code); + +/** + * @brief Creates a TsFileWriter for writing TsFiles. Review Comment: writing a TsFile ########## cpp/src/cwrapper/tsfile_cwrapper.cc: ########## @@ -19,292 +19,359 @@ #include "cwrapper/tsfile_cwrapper.h" +#include <file/write_file.h> #include <reader/qds_without_timegenerator.h> +#include <unistd.h> +#include <writer/tsfile_table_writer.h> #include "common/tablet.h" #include "reader/result_set.h" #include "reader/tsfile_reader.h" #include "writer/tsfile_writer.h" +#ifdef __cplusplus +extern "C" { +#endif + static bool is_init = false; -Tablet tablet_new_with_device(const char *device_id, char **column_name_list, - TSDataType *data_types, int column_num, - int max_rows) { - std::vector<std::string> measurement_list; - std::vector<common::TSDataType> data_type_list; - for (int i = 0; i < column_num; i++) { - measurement_list.emplace_back(column_name_list[i]); - data_type_list.push_back( - static_cast<common::TSDataType>(*(data_types + i))); +void init_tsfile_config() { + if (!is_init) { + common::init_config_value(); + is_init = true; + } +} + +WriteFile write_file_new(const char *pathname, ERRNO *err_code) { + int ret; + init_tsfile_config(); + + if (access(pathname, F_OK) == 0) { + *err_code = common::E_ALREADY_EXIST; + return nullptr; + } + + int flags = O_RDWR | O_CREAT | O_TRUNC; +#ifdef _WIN32 + flags |= O_BINARY; +#endif + mode_t mode = 0666; + storage::WriteFile *file = new storage::WriteFile; + ret = file->create(pathname, flags, mode); + *err_code = ret; + return file; +} + +TsFileWriter tsfile_writer_new(WriteFile file, TableSchema *schema, + ERRNO *err_code) { + init_tsfile_config(); + std::vector<common::ColumnSchema> column_schemas; + for (int i = 0; i < schema->column_num; i++) { + ColumnSchema cur_schema = schema->column_schemas[i]; + column_schemas.emplace_back(common::ColumnSchema( + cur_schema.column_name, + static_cast<common::TSDataType>(cur_schema.data_type), + static_cast<common::CompressionType>(cur_schema.compression), + static_cast<common::TSEncoding>(cur_schema.encoding), + static_cast<common::ColumnCategory>(cur_schema.column_category))); + } + + // There is no need to free table_schema. + storage::TableSchema *table_schema = + new storage::TableSchema(schema->table_name, column_schemas); + *err_code = common::E_OK; + return new storage::TsFileTableWriter( + static_cast<storage::WriteFile *>(file), table_schema); +} + +TsFileReader tsfile_reader_new(const char *pathname, ERRNO *err_code) { + init_tsfile_config(); + auto reader = new storage::TsFileReader(); + int ret = reader->open(pathname); + if (ret != common::E_OK) { + *err_code = ret; + delete reader; + return nullptr; } - auto *tablet = new storage::Tablet(device_id, &measurement_list, - &data_type_list, max_rows); - return tablet; + return reader; +} + +ERRNO tsfile_writer_close(TsFileWriter writer) { + auto *w = static_cast<storage::TsFileTableWriter *>(writer); + int ret = w->flush(); + if (ret != common::E_OK) { + return ret; + } + ret = w->close(); + if (ret != common::E_OK) { + return ret; + } + delete w; + return ret; } -Tablet tablet_new(const char **column_name_list, TSDataType *data_types, - uint32_t column_num) { +ERRNO tsfile_reader_close(TsFileReader reader) { + auto *ts_reader = static_cast<storage::TsFileReader *>(reader); + delete ts_reader; + return common::E_OK; +} + +Tablet tablet_new(char **column_name_list, TSDataType *data_types, + uint32_t column_num, uint32_t max_rows) { std::vector<std::string> measurement_list; std::vector<common::TSDataType> data_type_list; for (uint32_t i = 0; i < column_num; i++) { measurement_list.emplace_back(column_name_list[i]); data_type_list.push_back( static_cast<common::TSDataType>(*(data_types + i))); } - auto *tablet = new storage::Tablet("", &measurement_list, &data_type_list); - return tablet; + return new storage::Tablet(measurement_list, data_type_list, max_rows); } uint32_t tablet_get_cur_row_size(Tablet tablet) { return static_cast<storage::Tablet *>(tablet)->get_cur_row_size(); } ERRNO tablet_add_timestamp(Tablet tablet, uint32_t row_index, - timestamp timestamp) { + Timestamp timestamp) { return static_cast<storage::Tablet *>(tablet)->add_timestamp(row_index, timestamp); } #define TABLET_ADD_VALUE_BY_NAME_DEF(type) \ ERRNO tablet_add_value_by_name_##type(Tablet tablet, uint32_t row_index, \ const char *column_name, \ - type value) { \ + const type value) { \ return static_cast<storage::Tablet *>(tablet)->add_value( \ row_index, column_name, value); \ } - TABLET_ADD_VALUE_BY_NAME_DEF(int32_t); TABLET_ADD_VALUE_BY_NAME_DEF(int64_t); TABLET_ADD_VALUE_BY_NAME_DEF(float); TABLET_ADD_VALUE_BY_NAME_DEF(double); TABLET_ADD_VALUE_BY_NAME_DEF(bool); +ERRNO tablet_add_value_by_name_string(Tablet tablet, uint32_t row_index, + const char *column_name, + const char *value) { + return static_cast<storage::Tablet *>(tablet)->add_value( + row_index, column_name, common::String(value)); +} + #define TABLE_ADD_VALUE_BY_INDEX_DEF(type) \ ERRNO tablet_add_value_by_index_##type(Tablet tablet, uint32_t row_index, \ uint32_t column_index, \ - type value) { \ + const type value) { \ return static_cast<storage::Tablet *>(tablet)->add_value( \ row_index, column_index, value); \ } +ERRNO tablet_add_value_by_index_string(Tablet tablet, uint32_t row_index, + uint32_t column_index, + const char *value) { + return static_cast<storage::Tablet *>(tablet)->add_value( + row_index, column_index, common::String(value)); +} + TABLE_ADD_VALUE_BY_INDEX_DEF(int32_t); TABLE_ADD_VALUE_BY_INDEX_DEF(int64_t); TABLE_ADD_VALUE_BY_INDEX_DEF(float); TABLE_ADD_VALUE_BY_INDEX_DEF(double); TABLE_ADD_VALUE_BY_INDEX_DEF(bool); -void *tablet_get_value(Tablet tablet, uint32_t row_index, uint32_t schema_index, - TSDataType *type) { - common::TSDataType data_type; - void *result = static_cast<storage::Tablet *>(tablet)->get_value( - row_index, schema_index, data_type); - *type = static_cast<TSDataType>(data_type); - return result; -} - +/* // TsRecord API -TsRecord ts_record_new(const char *device_id, timestamp timestamp, - int timeseries_num) { - auto *record = new storage::TsRecord(timestamp, device_id, timeseries_num); - return record; +TsRecord ts_record_new(const char *device_id, Timestamp timestamp, + int timeseries_num) { +auto *record = new storage::TsRecord(timestamp, device_id, +timeseries_num); return record; } #define INSERT_DATA_INTO_TS_RECORD_BY_NAME_DEF(type) \ - ERRNO insert_data_into_ts_record_by_name_##type( \ - TsRecord data, const char *measurement_name, type value) { \ - auto *record = (storage::TsRecord *)data; \ - storage::DataPoint point(measurement_name, value); \ - if (record->points_.size() + 1 > record->points_.capacity()) \ - return common::E_BUF_NOT_ENOUGH; \ - record->points_.push_back(point); \ - return common::E_OK; \ - } +ERRNO insert_data_into_ts_record_by_name_##type( \ + TsRecord data, const char *measurement_name, type value) { \ + auto *record = (storage::TsRecord *)data; \ + storage::DataPoint point(measurement_name, value); \ + if (record->points_.size() + 1 > record->points_.capacity()) \ + return common::E_BUF_NOT_ENOUGH; \ + record->points_.push_back(point); \ + return common::E_OK; \ +} INSERT_DATA_INTO_TS_RECORD_BY_NAME_DEF(int32_t); INSERT_DATA_INTO_TS_RECORD_BY_NAME_DEF(int64_t); INSERT_DATA_INTO_TS_RECORD_BY_NAME_DEF(bool); INSERT_DATA_INTO_TS_RECORD_BY_NAME_DEF(float); INSERT_DATA_INTO_TS_RECORD_BY_NAME_DEF(double); -void init_tsfile_config() { - if (!is_init) { - common::init_config_value(); - is_init = true; - } -} - -TsFileReader tsfile_reader_new(const char *pathname, ERRNO *err_code) { - init_tsfile_config(); - auto reader = new storage::TsFileReader(); - int ret = reader->open(pathname); - if (ret != common::E_OK) { - *err_code = ret; - delete reader; - return nullptr; - } - return reader; -} - -TsFileWriter tsfile_writer_new(const char *pathname, ERRNO *err_code) { - init_tsfile_config(); - auto writer = new storage::TsFileWriter(); - int flags = O_WRONLY | O_CREAT | O_TRUNC; -#ifdef _WIN32 - flags |= O_BINARY; -#endif - int ret = writer->open(pathname, flags, 0644); - if (ret != common::E_OK) { - delete writer; - *err_code = ret; - return nullptr; - } - return writer; -} - TsFileWriter tsfile_writer_new_with_conf(const char *pathname, - const mode_t flag, ERRNO *err_code, - TsFileConf *conf) { - init_tsfile_config(); - auto *writer = new storage::TsFileWriter(); - const int ret = writer->open(pathname, O_CREAT | O_RDWR, flag); - if (ret != common::E_OK) { - delete writer; - *err_code = ret; - return nullptr; - } - return writer; + const mode_t flag, ERRNO *err_code, + TsFileConf *conf) { +init_tsfile_config(); +auto *writer = new storage::TsFileWriter(); +const int ret = writer->open(pathname, O_CREAT | O_RDWR, flag); +if (ret != common::E_OK) { + delete writer; + *err_code = ret; + return nullptr; } - -ERRNO tsfile_writer_close(TsFileWriter writer) { - auto *w = static_cast<storage::TsFileWriter *>(writer); - int ret = w->close(); - delete w; - return ret; +return writer; } -ERRNO tsfile_reader_close(TsFileReader reader) { - auto *ts_reader = static_cast<storage::TsFileReader *>(reader); - delete ts_reader; - return common::E_OK; +ERRNO tsfile_writer_register_table(TsFileWriter writer, TableSchema *schema) +{ +std::vector<storage::MeasurementSchema *> measurement_schemas; +std::vector<common::ColumnCategory> column_categories; +measurement_schemas.resize(schema->column_num); +for (int i = 0; i < schema->column_num; i++) { + ColumnSchema *cur_schema = schema->column_schemas + i; + measurement_schemas[i] = new storage::MeasurementSchema( + cur_schema->column_name, + static_cast<common::TSDataType>(cur_schema->data_type)); + column_categories.push_back( + static_cast<common::ColumnCategory>(cur_schema->column_category)); } - -ERRNO tsfile_writer_register_table(TsFileWriter writer, TableSchema *schema) { - std::vector<storage::MeasurementSchema *> measurement_schemas; - std::vector<common::ColumnCategory> column_categories; - measurement_schemas.resize(schema->column_num); - for (int i = 0; i < schema->column_num; i++) { - ColumnSchema *cur_schema = schema->column_schemas + i; - measurement_schemas[i] = new storage::MeasurementSchema( - cur_schema->column_name, - static_cast<common::TSDataType>(cur_schema->data_type)); - column_categories.push_back( - static_cast<common::ColumnCategory>(cur_schema->column_category)); - } - auto tsfile_writer = static_cast<storage::TsFileWriter *>(writer); - return tsfile_writer->register_table(std::make_shared<storage::TableSchema>( - schema->table_name, measurement_schemas, column_categories)); +auto tsfile_writer = static_cast<storage::TsFileWriter *>(writer); +return +tsfile_writer->register_table(std::make_shared<storage::TableSchema>( + schema->table_name, measurement_schemas, column_categories)); } ERRNO tsfile_writer_register_timeseries(TsFileWriter writer, - const char *device_id, - const TimeseriesSchema *schema) { - auto *w = static_cast<storage::TsFileWriter *>(writer); + const char *device_id, + const TimeseriesSchema *schema) { +auto *w = static_cast<storage::TsFileWriter *>(writer); - int ret = w->register_timeseries( - device_id, - storage::MeasurementSchema( - schema->timeseries_name, - static_cast<common::TSDataType>(schema->data_type), - static_cast<common::TSEncoding>(schema->encoding), - static_cast<common::CompressionType>(schema->compression))); - return ret; +int ret = w->register_timeseries( + device_id, + storage::MeasurementSchema( + schema->timeseries_name, + static_cast<common::TSDataType>(schema->data_type), + static_cast<common::TSEncoding>(schema->encoding), + static_cast<common::CompressionType>(schema->compression))); +return ret; } ERRNO tsfile_writer_register_device(TsFileWriter writer, - const device_schema *device_schema) { - auto *w = static_cast<storage::TsFileWriter *>(writer); - for (int column_id = 0; column_id < device_schema->timeseries_num; - column_id++) { - TimeseriesSchema schema = device_schema->timeseries_schema[column_id]; - const ERRNO ret = w->register_timeseries( - device_schema->device_name, - storage::MeasurementSchema( - schema.timeseries_name, - static_cast<common::TSDataType>(schema.data_type), - static_cast<common::TSEncoding>(schema.encoding), - static_cast<common::CompressionType>(schema.compression))); - if (ret != common::E_OK) { - return ret; - } + const device_schema *device_schema) { +auto *w = static_cast<storage::TsFileWriter *>(writer); +for (int column_id = 0; column_id < device_schema->timeseries_num; + column_id++) { + TimeseriesSchema schema = + device_schema->timeseries_schema[column_id]; const ERRNO ret = + w->register_timeseries( + device_schema->device_name, + storage::MeasurementSchema( + schema.timeseries_name, + static_cast<common::TSDataType>(schema.data_type), + static_cast<common::TSEncoding>(schema.encoding), + static_cast<common::CompressionType>(schema.compression))); + if (ret != common::E_OK) { + return ret; } - return common::E_OK; +} +return common::E_OK; } ERRNO tsfile_writer_write_ts_record(TsFileWriter writer, TsRecord data) { - auto *w = static_cast<storage::TsFileWriter *>(writer); - const storage::TsRecord *record = static_cast<storage::TsRecord *>(data); - const int ret = w->write_record(*record); - return ret; +auto *w = static_cast<storage::TsFileWriter *>(writer); +const storage::TsRecord *record = static_cast<storage::TsRecord *>(data); +const int ret = w->write_record(*record); +return ret; } ERRNO tsfile_writer_write_tablet(TsFileWriter writer, Tablet tablet) { - auto *w = static_cast<storage::TsFileWriter *>(writer); - const auto *tbl = static_cast<storage::Tablet *>(tablet); - return w->write_tablet(*tbl); +auto *w = static_cast<storage::TsFileWriter *>(writer); +const auto *tbl = static_cast<storage::Tablet *>(tablet); +return w->write_tablet(*tbl); } - -ERRNO tsfile_writer_flush_data(TsFileWriter writer) { - auto *w = static_cast<storage::TsFileWriter *>(writer); - return w->flush(); +*/ +ERRNO tsfile_writer_write(TsFileWriter writer, Tablet tablet) { + auto *w = static_cast<storage::TsFileTableWriter *>(writer); + auto *tbl = static_cast<storage::Tablet *>(tablet); + return w->write_table(*tbl); } -// Query +// ERRNO tsfile_writer_flush_data(TsFileWriter writer) { +// auto *w = static_cast<storage::TsFileWriter *>(writer); +// return w->flush(); +// } -ResultSet tsfile_reader_query_table(TsFileReader reader, const char *table_name, -char **columns, uint32_t column_num, - timestamp start_time, timestamp end_time) { - // TODO: Implement query table with tsfile reader. - return nullptr; -} +// Query -ResultSet tsfile_reader_query_device(TsFileReader reader, const char* device_name, - char** sensor_name, uint32_t sensor_num, - timestamp start_time, timestamp end_time) { +ResultSet tsfile_query_table(TsFileReader reader, const char *table_name, + char **columns, uint32_t column_num, + Timestamp start_time, Timestamp end_time, + ERRNO *err_code) { auto *r = static_cast<storage::TsFileReader *>(reader); - std::vector<std::string> selected_paths; - selected_paths.reserve(sensor_num); - for (uint32_t i = 0; i < sensor_num; i++) { - selected_paths.push_back(std::string(device_name) + "." + std::string(sensor_name[i])); + storage::ResultSet *table_result_set = nullptr; + std::vector<std::string> column_names; + for (uint32_t i = 0; i < column_num; i++) { + column_names.emplace_back(columns[i]); + } + *err_code = r->query(table_name, column_names, start_time, end_time, + table_result_set); + return table_result_set; +} + +// ResultSet tsfile_reader_query_device(TsFileReader reader, +// const char *device_name, +// char **sensor_name, uint32_t sensor_num, +// Timestamp start_time, Timestamp +// end_time) { +// auto *r = static_cast<storage::TsFileReader *>(reader); +// std::vector<std::string> selected_paths; +// selected_paths.reserve(sensor_num); +// for (uint32_t i = 0; i < sensor_num; i++) { +// selected_paths.push_back(std::string(device_name) + "." + +// std::string(sensor_name[i])); +// } +// storage::ResultSet *qds = nullptr; +// r->query(selected_paths, start_time, end_time, qds); +// return qds; +// } + +bool tsfile_result_set_next(ResultSet result_set, ERRNO *err_code) { + auto *r = static_cast<storage::TableResultSet *>(result_set); + bool has_next = true; + int ret = common::E_OK; + ret = r->next(has_next); + *err_code = ret; + if (ret != common::E_OK) { + return false; } - storage::ResultSet *qds = nullptr; - r->query(selected_paths, start_time, end_time, qds); - return qds; -} - -bool tsfile_result_set_has_next(ResultSet result_set) { - auto *r = static_cast<storage::QDSWithoutTimeGenerator *>(result_set); - bool has_next = false; - r->next(has_next); return has_next; } #define TSFILE_RESULT_SET_GET_VALUE_BY_NAME_DEF(type) \ type tsfile_result_set_get_value_by_name_##type(ResultSet result_set, \ const char *column_name) { \ - auto *r = static_cast<storage::ResultSet *>(result_set); \ + auto *r = static_cast<storage::TableResultSet *>(result_set); \ return r->get_value<type>(column_name); \ } + TSFILE_RESULT_SET_GET_VALUE_BY_NAME_DEF(bool); TSFILE_RESULT_SET_GET_VALUE_BY_NAME_DEF(int32_t); TSFILE_RESULT_SET_GET_VALUE_BY_NAME_DEF(int64_t); TSFILE_RESULT_SET_GET_VALUE_BY_NAME_DEF(float); TSFILE_RESULT_SET_GET_VALUE_BY_NAME_DEF(double); +char *tsfile_result_set_get_value_by_name_string(ResultSet result_set, + const char *column_name) { + auto *r = static_cast<storage::TableResultSet *>(result_set); + common::String *ret = r->get_value<common::String *>(column_name); + // Caller should free return's char* 's space. Review Comment: Make sure this comment exists in the declaration. ########## cpp/src/writer/tsfile_writer.cc: ########## @@ -281,6 +281,31 @@ struct MeasurementNamesFromTablet { } }; +int TsFileWriter::do_check_and_prepare_tablet(Tablet &tablet) { + if (tablet.column_categories_.empty()) { + auto &schema_map = io_writer_->get_schema()->table_schema_map_; + auto table_schema_it = schema_map.find(tablet.get_table_name()); + auto table_schema = table_schema_it->second; + uint32_t column_cnt = tablet.get_column_count(); + for (uint32_t i = 0; i < column_cnt; i++) { + for (uint32_t i = 0; i < column_cnt; i++) { Review Comment: Check this ########## cpp/src/cwrapper/tsfile_cwrapper.h: ########## @@ -109,94 +118,246 @@ typedef void* TsRecord; typedef void* ResultSet; typedef int32_t ERRNO; -typedef int64_t timestamp; +typedef int64_t Timestamp; -#ifdef __cplusplus -extern "C" { -#endif +/*--------------------------TsFile Reader and Writer------------------------ */ + +/** + * @brief Creates a file for writing. + * + * @param pathname Target file path to create. + * @param err_code [out] E_OK(0), or check error code in errno_define.h. + * + * @return WriteFile Valid handle on success. + * + * @note Call free_write_file() to release resources. + */ + +WriteFile write_file_new(const char* pathname, ERRNO* err_code); + +/** + * @brief Creates a TsFileWriter for writing TsFiles. + * + * @param file Target file where the table data will be written. + * @param schema Table schema definition. + * - Ownership: Caller must free it after writer creating. Review Comment: after writer is closed? ########## cpp/src/cwrapper/tsfile_cwrapper.h: ########## @@ -109,94 +118,246 @@ typedef void* TsRecord; typedef void* ResultSet; typedef int32_t ERRNO; -typedef int64_t timestamp; +typedef int64_t Timestamp; -#ifdef __cplusplus -extern "C" { -#endif +/*--------------------------TsFile Reader and Writer------------------------ */ + +/** + * @brief Creates a file for writing. + * + * @param pathname Target file path to create. + * @param err_code [out] E_OK(0), or check error code in errno_define.h. + * + * @return WriteFile Valid handle on success. + * + * @note Call free_write_file() to release resources. Review Comment: Call tsfile_writer_close() before calling free_write_file() -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@tsfile.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org