This is an automated email from the ASF dual-hosted git repository. colinlee pushed a commit to branch colin_example_c_cpp in repository https://gitbox.apache.org/repos/asf/tsfile.git
commit 6a0bebba90022c2fcab1fe9b4cb8255b479fc87d Author: colin <shuoli...@163.com> AuthorDate: Wed Feb 26 19:03:28 2025 +0800 fix c --- cpp/examples/c_examples/demo_write.c | 29 +- cpp/src/common/schema.h | 4 + cpp/src/cwrapper/errno_define.h | 77 +++++ cpp/src/cwrapper/tsfile_cwrapper.cc | 588 +++++++++++++++++++---------------- cpp/src/cwrapper/tsfile_cwrapper.h | 322 +++++++++++++++---- cpp/test/cwrapper/cwrapper_test.cc | 182 +++++------ 6 files changed, 757 insertions(+), 445 deletions(-) diff --git a/cpp/examples/c_examples/demo_write.c b/cpp/examples/c_examples/demo_write.c index 69d4476c..292bb6e2 100644 --- a/cpp/examples/c_examples/demo_write.c +++ b/cpp/examples/c_examples/demo_write.c @@ -27,31 +27,32 @@ 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_TEXT, + .column_category = TAG}, + (ColumnSchema){.column_name = "id2", + .data_type = TS_DATATYPE_TEXT, + .column_category = TAG}, + (ColumnSchema){.column_name = "s1", + .data_type = TS_DATATYPE_INT32, + .column_category = FIELD}}}; // Create tsfile writer with specify path. - TsFileWriter writer = tsfile_writer_new("test.tsfile", &code); + TsFileWriter writer = tsfile_writer_new("test.tsfile", &table_schema, &code); HANDLE_ERROR(code); // Table schema. - TableSchema table_schema = {.table_name = table_name, - .column_schemas = (ColumnSchema[]){ - (ColumnSchema){.column_name = "id1", - .data_type = TS_DATATYPE_TEXT, - .column_category = TAG}, - (ColumnSchema){.column_name = "id2", - .data_type = TS_DATATYPE_TEXT, - .column_category = TAG}, - (ColumnSchema){.column_name = "s1", - .data_type = TS_DATATYPE_INT32, - .column_category = FIELD}}}; + // Register a table with tsfile writer. code = tsfile_writer_register_table(writer, &table_schema); HANDLE_ERROR(code); // Create tablet to insert data. - Tablet tablet = tablet_new_with_device( - table_name, (char*[]){"id1", "id2", "s1"}, + Tablet tablet = tablet_new( + (char*[]){"id1", "id2", "s1"}, (TSDataType[]){TS_DATATYPE_TEXT, TS_DATATYPE_TEXT, TS_DATATYPE_INT32}, 3, 1024); diff --git a/cpp/src/common/schema.h b/cpp/src/common/schema.h index 15822041..43cefbc8 100644 --- a/cpp/src/common/schema.h +++ b/cpp/src/common/schema.h @@ -280,6 +280,10 @@ class TableSchema { return ret; } + int32_t get_columns_num() const { + return column_schemas_.size(); + } + int find_column_index(const std::string &column_name) { std::string lower_case_column_name = to_lower(column_name); auto it = column_pos_index_.find(lower_case_column_name); diff --git a/cpp/src/cwrapper/errno_define.h b/cpp/src/cwrapper/errno_define.h new file mode 100644 index 00000000..cf7ad1f4 --- /dev/null +++ b/cpp/src/cwrapper/errno_define.h @@ -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. + */ + +#ifndef CWRAPPER_ERRNO_DEFINRET_H +#define CWRAPPER_ERRNO_DEFINRET_H + +#define RET_OK 0 +#define RET_OOM 1 +#define RET_NOT_EXIST 2 +#define RET_ALREADY_EXIST 3 +#define RET_INVALID_ARG 4 +#define RET_OUT_OF_RANGE 5 +#define RET_PARTIAL_READ 6 +#define RET_NET_BIND_ERR 7 +#define RET_NET_SOCKET_ERR 8 +#define RET_NET_EPOLL_ERR 9 +#define RET_NET_EPOLL_WAIT_ERR 10 +#define RET_NET_RECV_ERR 11 +#define RET_NET_ACCEPT_ERR 12 +#define RET_NET_FCNTL_ERR 13 +#define RET_NET_LISTEN_ERR 14 +#define RET_NET_SEND_ERR 15 +#define RET_PIPRET_ERR 16 +#define RET_THREAD_CREATRET_ERR 17 +#define RET_MUTEX_ERR 18 +#define RET_COND_ERR 19 +#define RET_OVERFLOW 20 +#define RET_NO_MORRET_DATA 21 +#define RET_OUT_OF_ORDER 22 +#define RET_TSBLOCK_TYPRET_NOT_SUPPORTED 23 +#define RET_TSBLOCK_DATA_INCONSISTENCY 24 +#define RET_DDL_UNKNOWN_TYPE 25 +#define RET_TYPRET_NOT_SUPPORTED 26 +#define RET_TYPRET_NOT_MATCH 27 +#define RET_FILRET_OPEN_ERR 28 +#define RET_FILRET_CLOSRET_ERR 29 +#define RET_FILRET_WRITRET_ERR 30 +#define RET_FILRET_READ_ERR 31 +#define RET_FILRET_SYNC_ERR 32 +#define RET_TSFILRET_WRITER_META_ERR 33 +#define RET_FILRET_STAT_ERR 34 +#define RET_TSFILRET_CORRUPTED 35 +#define RET_BUF_NOT_ENOUGH 36 +#define RET_INVALID_PATH 37 +#define RET_NOT_MATCH 38 +#define RET_JSON_INVALID 39 +#define RET_NOT_SUPPORT 40 +#define RET_PARSER_ERR 41 +#define RET_ANALYZRET_ERR 42 +#define RET_INVALID_DATA_POINT 43 +#define RET_DEVICRET_NOT_EXIST 44 +#define RET_MEASUREMENT_NOT_EXIST 45 +#define RET_INVALID_QUERY 46 +#define RET_SDK_QUERY_OPTIMIZRET_ERR 47 +#define RET_COMPRESS_ERR 48 +#define RET_TABLRET_NOT_EXIST 49 +#define RET_COLUMN_NOT_EXIST 50 +#define RET_UNSUPPORTED_ORDER 51 +#define RET_INVALID_NODRET_TYPE 52 + +#endif /* CWRAPPER_ERRNO_DEFINRET_H */ \ No newline at end of file diff --git a/cpp/src/cwrapper/tsfile_cwrapper.cc b/cpp/src/cwrapper/tsfile_cwrapper.cc index 50fba728..048b4dfa 100644 --- a/cpp/src/cwrapper/tsfile_cwrapper.cc +++ b/cpp/src/cwrapper/tsfile_cwrapper.cc @@ -19,7 +19,9 @@ #include "cwrapper/tsfile_cwrapper.h" +#include <file/write_file.h> #include <reader/qds_without_timegenerator.h> +#include <writer/tsfile_table_writer.h> #include "common/tablet.h" #include "reader/result_set.h" @@ -32,23 +34,81 @@ extern "C" { 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; } - auto *tablet = new storage::Tablet(device_id, &measurement_list, - &data_type_list, max_rows); - return tablet; } -Tablet tablet_new(const char **column_name_list, TSDataType *data_types, - uint32_t column_num) { +TsFileWriter tsfile_writer_new(const char *pathname, TableSchema *schema, + ERRNO *err_code) { + int ret; + init_tsfile_config(); + int flags = O_WRONLY | 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); + if (ret != common::E_OK) { + *err_code = ret; + return nullptr; + } + + 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); + return new storage::TsFileTableWriter(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; + } + 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; +} + +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++) { @@ -56,8 +116,7 @@ Tablet tablet_new(const char **column_name_list, TSDataType *data_types, 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) { @@ -73,267 +132,228 @@ ERRNO tablet_add_timestamp(Tablet tablet, uint32_t row_index, #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); \ } - -ERRNO tablet_add_value_by_name_string(Tablet tablet, uint32_t row_index, - const char* column_name, char* value) { - return static_cast<storage::Tablet *>(tablet)->add_value( - row_index, column_name, common::String(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, char* value) { + 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; -} - -#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; \ - } - -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; -} - -ERRNO tsfile_writer_close(TsFileWriter writer) { - auto *w = static_cast<storage::TsFileWriter *>(writer); - int ret = w->close(); - delete w; - return ret; -} - -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)); - } - 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); - - 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; - } - } - 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; -} - -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); -} - -ERRNO tsfile_writer_flush_data(TsFileWriter writer) { - auto *w = static_cast<storage::TsFileWriter *>(writer); - return w->flush(); -} +// +// // 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; +// } +// +// #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; \ +// } +// +// 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); +// +// 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; +// } +// +// 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)); +// } +// +// ERRNO tsfile_writer_register_timeseries(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; +// } +// +// 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; +// } +// } +// 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; +// } +// +// 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); +// } +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); +} + +// ERRNO tsfile_writer_flush_data(TsFileWriter writer) { +// auto *w = static_cast<storage::TsFileWriter *>(writer); +// return w->flush(); +// } // Query -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; -} - -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) { 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 (int i = 0; i < column_num; i++) { + column_names.emplace_back(columns[i]); } - 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); + 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 = false; - r->next(has_next); + int ret = common::E_OK; + ret = r->next(has_next); + *err_code = ret; + if (ret != common::E_OK) { + return false; + } 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::ResultSet *>(result_set); + 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. return strdup(ret->buf_); } -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); #define TSFILE_RESULT_SET_GET_VALUE_BY_INDEX_DEF(type) \ type tsfile_result_set_get_value_by_index_##type(ResultSet result_set, \ uint32_t column_index) { \ - auto *r = static_cast<storage::ResultSet *>(result_set); \ + auto *r = static_cast<storage::TableResultSet *>(result_set); \ return r->get_value<type>(column_index); \ } @@ -342,9 +362,10 @@ TSFILE_RESULT_SET_GET_VALUE_BY_INDEX_DEF(int64_t); 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::ResultSet *>(result_set); + 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. return strdup(ret->buf_); @@ -352,18 +373,18 @@ char *tsfile_result_set_get_value_by_index_string(ResultSet result_set, 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); ResultSetMetaData meta_data; std::shared_ptr<storage::ResultSetMetadata> result_set_metadata = r->get_metadata(); @@ -381,55 +402,88 @@ 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 < 0 || 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; + } return result_set.data_types[column_index]; } -int tsfile_result_set_meta_get_column_num(ResultSetMetaData result_set) { +int tsfile_result_set_metadata_get_column_num(ResultSetMetaData result_set) { return result_set.column_num; } -TableSchema tsfile_reader_get_table_schema(TsFileReader reader, - const char *table_name) { - // TODO: Implement get table schema with tsfile reader. - return TableSchema(); -} +// TableSchema tsfile_reader_get_table_schema(TsFileReader reader, +// const char *table_name) { +// // TODO: Implement get table schema with tsfile reader. +// return TableSchema(); +// } +// +// DeviceSchema tsfile_reader_get_device_schema(TsFileReader reader, +// const char *device_id) { +// auto *r = static_cast<storage::TsFileReader *>(reader); +// std::vector<storage::MeasurementSchema> measurement_schemas; +// r->get_timeseries_schema( +// std::make_shared<storage::StringArrayDeviceID>(device_id), +// measurement_schemas); +// DeviceSchema schema; +// schema.device_name = strdup(device_id); +// schema.timeseries_num = measurement_schemas.size(); +// schema.timeseries_schema = static_cast<TimeseriesSchema *>( +// malloc(sizeof(TimeseriesSchema) * schema.timeseries_num)); +// for (int i = 0; i < schema.timeseries_num; i++) { +// schema.timeseries_schema[i].timeseries_name = +// strdup(measurement_schemas[i].measurement_name_.c_str()); +// schema.timeseries_schema[i].data_type = +// static_cast<TSDataType>(measurement_schemas[i].data_type_); +// schema.timeseries_schema[i].compression = +// static_cast<CompressionType>( +// measurement_schemas[i].compression_type_); +// schema.timeseries_schema[i].encoding = +// static_cast<TSEncoding>(measurement_schemas[i].encoding_); +// } +// return schema; +// } -DeviceSchema tsfile_reader_get_device_schema(TsFileReader reader, - const char *device_id) { +TableSchema *tsfile_reader_get_all_table_schemas(TsFileReader reader, + uint32_t *size) { auto *r = static_cast<storage::TsFileReader *>(reader); - std::vector<storage::MeasurementSchema> measurement_schemas; - r->get_timeseries_schema( - std::make_shared<storage::StringArrayDeviceID>(device_id), - measurement_schemas); - DeviceSchema schema; - schema.device_name = strdup(device_id); - schema.timeseries_num = measurement_schemas.size(); - schema.timeseries_schema = static_cast<TimeseriesSchema *>( - malloc(sizeof(TimeseriesSchema) * schema.timeseries_num)); - for (int i = 0; i < schema.timeseries_num; i++) { - schema.timeseries_schema[i].timeseries_name = - strdup(measurement_schemas[i].measurement_name_.c_str()); - schema.timeseries_schema[i].data_type = - static_cast<TSDataType>(measurement_schemas[i].data_type_); - schema.timeseries_schema[i].compression = static_cast<CompressionType>( - measurement_schemas[i].compression_type_); - schema.timeseries_schema[i].encoding = - static_cast<TSEncoding>(measurement_schemas[i].encoding_); + auto table_schemas = r->get_all_table_schemas(); + size_t table_num = table_schemas.size(); + TableSchema *ret = + static_cast<TableSchema *>(malloc(sizeof(TableSchema) * table_num)); + for (size_t i = 0; i < table_schemas.size(); i++) { + ret[i].table_name = strdup(table_schemas[i]->get_table_name().c_str()); + int column_num = table_schemas[i]->get_columns_num(); + ret[i].column_num = column_num; + ret[i].column_schemas = static_cast<ColumnSchema *>( + malloc(column_num * sizeof(ColumnSchema))); + auto column_schemas = table_schemas[i]->get_measurement_schemas(); + for (int i = 0; i < column_num; i++) { + ret[i].column_schemas[i].column_name = + strdup(column_schemas[i]->measurement_name_.c_str()); + ret[i].column_schemas[i].data_type = + static_cast<TSDataType>(column_schemas[i]->data_type_); + ret[i].column_schemas[i].encoding = + static_cast<TSEncoding>(column_schemas[i]->encoding_); + ret[i].column_schemas[i].compression = static_cast<CompressionType>( + column_schemas[i]->compression_type_); + ret[i].column_schemas[i].column_category = + static_cast<ColumnCategory>( + table_schemas[i]->get_column_categories()[i]); + } } - return schema; -} - -TableSchema *tsfile_reader_get_all_table_schemas(TsFileReader reader, - uint32_t *num) { - // TODO: Implement get all table schemas. - return nullptr; + *size = table_num; + return ret; } // delete pointer diff --git a/cpp/src/cwrapper/tsfile_cwrapper.h b/cpp/src/cwrapper/tsfile_cwrapper.h index f0e4cdc6..fffb7b59 100644 --- a/cpp/src/cwrapper/tsfile_cwrapper.h +++ b/cpp/src/cwrapper/tsfile_cwrapper.h @@ -24,8 +24,8 @@ extern "C" { #endif #include <stdbool.h> -#include <sys/stat.h> #include <stdint.h> +#include <sys/stat.h> typedef enum { TS_DATATYPE_BOOLEAN = 0, @@ -72,6 +72,8 @@ typedef enum column_category { TAG = 0, FIELD = 1 } ColumnCategory; typedef struct column_schema { char* column_name; TSDataType data_type; + CompressionType compression; + TSEncoding encoding; ColumnCategory column_category; } ColumnSchema; @@ -116,37 +118,131 @@ typedef void* ResultSet; typedef int32_t ERRNO; typedef int64_t Timestamp; +/*--------------------------TsFile Reader and Writer------------------------ */ + +/** + * @brief Creates a TsFileWriter for writing TsFiles. + * + * @param pathname Target TsFile path. Must be a valid path. + * @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(const char* pathname, TableSchema* schema, + ERRNO* err_code); + +/** + * @brief Creates a TsFileReader for reading TsFiles. + * + * @param pathname Source TsFiles path. Must be a valid path. + * @param err_code E_OK(0), or check error code in errno_define.h. + * @return TsFileReader Valid handle on success, NULL on failure. + * + * @note Call tsfile_reader_close() to release resources. + */ +TsFileReader tsfile_reader_new(const char* pathname, ERRNO* err_code); + +/** + * @brief Releases resources associated with a TsFileWriter. + * + * @param writer [in] Writer handle obtained from tsfile_writer_new(). + * After call: handle becomes invalid and must not be reused. + * @return ERRNO - E_OK(0) on success, check error code in errno_define.h. + */ +ERRNO tsfile_writer_close(TsFileWriter writer); + +/** + * @brief Releases resources associated with a TsFileReader. + * + * @param reader [in] Reader handle obtained from tsfile_reader_new(). + * After call: + * Handle becomes invalid and must not be reused. + * Result_set obtained by this handle becomes invalid. + * @return ERRNO - E_OK(0) on success, or check error code in errno_define.h. + */ +ERRNO tsfile_reader_close(TsFileReader reader); /*--------------------------Tablet API------------------------ */ -Tablet tablet_new_with_device(const char* device_id, char** column_name_list, - TSDataType* data_types, int column_num, - int max_rows); -Tablet tablet_new(const char** column_name_list, TSDataType* data_types, - uint32_t column_num); +/** + * @brief Creates a Tablet for batch data. + * + * @param column_name_list [in] Column names array. Size=column_num. + * @param data_types [in] Data types array. Size=column_num. + * @param column_num [in] Number of columns. Must be ≥1. + * @param max_rows [in] Pre-allocated row capacity. Must be ≥1. + * @return Tablet Valid handle. + * @note Call free_tablet() to release resources. + */ +Tablet tablet_new(char** column_name_list, TSDataType* data_types, + uint32_t column_num, uint32_t max_rows); +/** + * @brief Gets current row count in the Tablet. + * + * @param tablet [in] Valid Tablet handle. + * @return uint32_t Row count (0 to max_rows-1). + */ uint32_t tablet_get_cur_row_size(Tablet tablet); +/** + * @brief Assigns timestamp to a row in the Tablet. + * + * @param tablet [in] Valid Tablet handle. + * @param row_index [in] Target row (0 ≤ index < max_rows). + * @param timestamp [in] Timestamp with int64_t type. + * @return ERRNO - E_OK(0)/E_OUT_OF_RANGE(5) or check errno_define.h. + */ ERRNO tablet_add_timestamp(Tablet tablet, uint32_t row_index, Timestamp timestamp); +/** + * @brief Adds a value to a Tablet row by column name (generic types). + * + * @param tablet [in] Valid Tablet handle. + * @param row_index [in] Target row (0 ≤ index < max_rows). + * @param column_name [in] Existing column name from Tablet schema. + * @param value [in] Value to add. Type must match column schema. + * @return ERRNO - E_OK(0) or check errno_define.h. + * + * @note Generated for types: int32_t, int64_t, float, double, bool + */ #define TABLET_ADD_VALUE_BY_NAME(type) \ ERRNO tablet_add_value_by_name_##type(Tablet tablet, uint32_t row_index, \ - const char* column_name, type value); - + const char* column_name, \ + const type value); TABLET_ADD_VALUE_BY_NAME(int32_t); TABLET_ADD_VALUE_BY_NAME(int64_t); TABLET_ADD_VALUE_BY_NAME(float); TABLET_ADD_VALUE_BY_NAME(double); TABLET_ADD_VALUE_BY_NAME(bool); +/** + * @brief Adds a string value to a Tablet row by column name. + * + * @param value [in] Null-terminated string. Ownership remains with caller. + * @return ERRNO. + */ ERRNO tablet_add_value_by_name_string(Tablet tablet, uint32_t row_index, - const char* column_name, char* value); + const char* column_name, + const char* value); +/** + * @brief Adds a value to a Tablet row by column index (generic types). + * + * @param column_index [in] Column position (0 ≤ index < column_num). + * @return ERRNO - E_OK(0) or check errno_define.h. + * + * @note Generated for types: int32_t, int64_t, float, double, bool + */ #define TABLE_ADD_VALUE_BY_INDEX(type) \ ERRNO tablet_add_value_by_index_##type(Tablet tablet, uint32_t row_index, \ - uint32_t column_index, type value); + uint32_t column_index, const type value); TABLE_ADD_VALUE_BY_INDEX(int32_t); TABLE_ADD_VALUE_BY_INDEX(int64_t); @@ -154,58 +250,92 @@ TABLE_ADD_VALUE_BY_INDEX(float); TABLE_ADD_VALUE_BY_INDEX(double); TABLE_ADD_VALUE_BY_INDEX(bool); +/** + * @brief Adds a string value to a Tablet row by column index. + * + * @param value [in] Null-terminated string. Copied internally. + */ ERRNO tablet_add_value_by_index_string(Tablet tablet, uint32_t row_index, - uint32_t column_index, char* value); - -void* tablet_get_value(Tablet tablet, uint32_t row_index, uint32_t schema_index, - TSDataType* type); - -/*--------------------------TsRecord API------------------------ */ -TsRecord ts_record_new(const char* device_id, Timestamp timestamp, - int timeseries_num); - -#define INSERT_DATA_INTO_TS_RECORD_BY_NAME(type) \ - ERRNO insert_data_into_ts_record_by_name_##type( \ - TsRecord data, const char* measurement_name, type value); + uint32_t column_index, const char* value); + +// /*--------------------------TsRecord API------------------------ */ +// TsRecord ts_record_new(const char* device_id, Timestamp timestamp, +// int timeseries_num); +// +// #define INSERT_DATA_INTO_TS_RECORD_BY_NAME(type) \ +// ERRNO insert_data_into_ts_record_by_name_##type( \ +// TsRecord data, const char* measurement_name, type value); +// +// INSERT_DATA_INTO_TS_RECORD_BY_NAME(int32_t); +// INSERT_DATA_INTO_TS_RECORD_BY_NAME(int64_t); +// INSERT_DATA_INTO_TS_RECORD_BY_NAME(bool); +// INSERT_DATA_INTO_TS_RECORD_BY_NAME(float); +// INSERT_DATA_INTO_TS_RECORD_BY_NAME(double); -INSERT_DATA_INTO_TS_RECORD_BY_NAME(int32_t); -INSERT_DATA_INTO_TS_RECORD_BY_NAME(int64_t); -INSERT_DATA_INTO_TS_RECORD_BY_NAME(bool); -INSERT_DATA_INTO_TS_RECORD_BY_NAME(float); -INSERT_DATA_INTO_TS_RECORD_BY_NAME(double); +/*--------------------------TsFile Writer Register------------------------ */ +// ERRNO tsfile_writer_register_table(TsFileWriter writer, TableSchema* schema); +// ERRNO tsfile_writer_register_timeseries(TsFileWriter writer, +// const char* device_id, +// const TimeseriesSchema* schema); +// ERRNO tsfile_writer_register_device(TsFileWriter writer, +// const DeviceSchema* device_schema); -/*--------------------------TsFile Reader and Writer------------------------ */ -TsFileReader tsfile_reader_new(const char* pathname, ERRNO* err_code); -TsFileWriter tsfile_writer_new(const char* pathname, ERRNO* err_code); -TsFileWriter tsfile_writer_new_with_conf(const char* pathname, mode_t flag, - ERRNO* err_code, TsFileConf* conf); +/*-------------------TsFile Writer write data------------------ */ -ERRNO tsfile_writer_close(TsFileWriter writer); -ERRNO tsfile_reader_close(TsFileReader reader); +/** + * @brief Writes data from a Tablet to the TsFile. + * + * @param writer [in] Valid TsFileWriter handle. Must be initialized. + * @param tablet [in] Tablet containing data. Should be freed after successful + * write. + * @return ERRNO - E_OK(0), or check error code in errno_define.h. + * + */ -/*--------------------------TsFile Writer Register------------------------ */ -ERRNO tsfile_writer_register_table(TsFileWriter writer, TableSchema* schema); -ERRNO tsfile_writer_register_timeseries(TsFileWriter writer, - const char* device_id, - const TimeseriesSchema* schema); -ERRNO tsfile_writer_register_device(TsFileWriter writer, - const DeviceSchema* device_schema); - -/*-------------------TsFile Writer write and flush data------------------ */ -ERRNO tsfile_writer_write_tablet(TsFileWriter writer, Tablet tablet); -ERRNO tsfile_writer_write_ts_record(TsFileWriter writer, TsRecord record); -ERRNO tsfile_writer_flush_data(TsFileWriter writer); +ERRNO tsfile_writer_write(TsFileWriter writer, Tablet tablet); +// ERRNO tsfile_writer_write_tablet(TsFileWriter writer, Tablet tablet); +// ERRNO tsfile_writer_write_ts_record(TsFileWriter writer, TsRecord record); +// ERRNO tsfile_writer_flush_data(TsFileWriter writer); /*-------------------TsFile reader query data------------------ */ -ResultSet tsfile_reader_query_table(TsFileReader reader, const char* table_name, - char** columns, uint32_t column_num, - Timestamp start_time, Timestamp end_time); -ResultSet tsfile_reader_query_device(TsFileReader reader, - const char* device_name, - char** sensor_name, uint32_t sensor_num, - Timestamp start_time, Timestamp end_time); -bool tsfile_result_set_has_next(ResultSet result_set); +/** + * @brief Queries time series data from a specific table within time range. + * + * @param reader [in] Valid TsFileReader handle from tsfile_reader_new(). + * @param table_name [in] Target table name. Must exist in the TS file. + * @param columns [in] Array of column names to fetch. + * @param column_num [in] Number of columns in array. + * @param start_time [in] Start timestamp. + * @param end_time [in] End timestamp. Must ≥ start_time. + * @return ResultSet Query results handle. Must be freed with + * free_tsfile_result_set(). + */ +ResultSet tsfile_query_table(TsFileReader reader, const char* table_name, + char** columns, uint32_t column_num, + Timestamp start_time, Timestamp end_time); +// ResultSet tsfile_reader_query_device(TsFileReader reader, +// const char* device_name, +// char** sensor_name, uint32_t sensor_num, +// Timestamp start_time, Timestamp +// end_time); + +/** + * @brief Check and fetch the next row in the ResultSet. + * + * @param result_set [in] Valid ResultSet handle. + * @return bool - true: Row available, false: End of data or error. + */ +bool tsfile_result_set_next(ResultSet result_set, ERRNO* error_code); + +/** + * @brief Gets value from current row by column name (generic types). + * + * @param result_set [in] Valid ResultSet with active row (after next()=true). + * @param column_name [in] Existing column name in result schema. + * @return type-value, return type-specific value. + * @note Generated for: bool, int32_t, int64_t, float, double + */ #define TSFILE_RESULT_SET_GET_VALUE_BY_NAME(type) \ type tsfile_result_set_get_value_by_name_##type(ResultSet result_set, \ const char* column_name) @@ -215,9 +345,24 @@ TSFILE_RESULT_SET_GET_VALUE_BY_NAME(int64_t); TSFILE_RESULT_SET_GET_VALUE_BY_NAME(float); TSFILE_RESULT_SET_GET_VALUE_BY_NAME(double); +/** + * @brief Gets string value from current row by column name. + * + * @return char* - String pointer. Caller must free this ptr after usage. + */ char* tsfile_result_set_get_value_by_name_string(ResultSet result_set, const char* column_name); +/** + * @brief Gets value from current row by column_index[0 <= column_index << + * column_num] (generic types). + * + * @param result_set [in] Valid ResultSet with active row (after next()=true). + * @param column_name [in] Existing column index in result schema. + * @return type-value, return type-specific value. + * @note Generated for: bool, int32_t, int64_t, float, double + */ + #define TSFILE_RESULT_SET_GET_VALUE_BY_INDEX(type) \ type tsfile_result_set_get_value_by_index_##type(ResultSet result_set, \ uint32_t column_index); @@ -228,29 +373,76 @@ TSFILE_RESULT_SET_GET_VALUE_BY_INDEX(float); TSFILE_RESULT_SET_GET_VALUE_BY_INDEX(double); TSFILE_RESULT_SET_GET_VALUE_BY_INDEX(bool); +/** + * @brief Gets string value from current row by column index. + * + * @return char* - String pointer. Caller must free this ptr after usage. + */ char* tsfile_result_set_get_value_by_index_string(ResultSet result_set, - uint32_t column_index); + uint32_t column_index); + +/** + * @brief Checks if the current row's column value is NULL by column name. + * + * @param result_set [in] Valid ResultSet with active row (after next()=true). + * @param column_name [in] Existing column name in result schema. + * @return bool - true: Value is NULL or column not found, false: Valid value. + */ bool tsfile_result_set_is_null_by_name(ResultSet result_set, const char* column_name); +/** + * @brief Checks if the current row's column value is NULL by column index. + * + * @param column_index [in] Column position (0 ≤ index < result_column_count). + * @return bool - true: Value is NULL or index out of range, false: Valid value. + */ bool tsfile_result_set_is_null_by_index(ResultSet result_set, uint32_t column_index); +/*-------------------TsFile reader query metadata------------------ */ + +/** + * @brief Retrieves metadata describing the ResultSet's schema. + * + * @param result_set [in] Valid ResultSet handle. + * @return ResultSetMetaData Metadata handle. Caller should free the + * ResultSetMataData after usage. + */ ResultSetMetaData tsfile_result_set_get_metadata(ResultSet result_set); -char* tsfile_result_set_meta_get_column_name(ResultSetMetaData result_set, - uint32_t column_index); -TSDataType tsfile_result_set_meta_get_data_type(ResultSetMetaData result_set, - uint32_t column_index); -int tsfile_result_set_meta_get_column_num(ResultSetMetaData result_set); + +/** + * @brief Gets column name by index from metadata. + * + * @param column_index [in] Column position (0 ≤ index < column_num). + * @return const char* Read-only string. NULL if index invalid. + */ +char* tsfile_result_set_metadata_get_column_name(ResultSetMetaData result_set, + uint32_t column_index); + +/** + * @brief Gets column data type by index from metadata. + * + * @return TSDataType Returns TS_DATATYPE_INVALID(255) if index invalid. + */ +TSDataType tsfile_result_set_metadata_get_data_type( + ResultSetMetaData result_set, uint32_t column_index); + +/** + * @brief Gets total number of columns in the result schema. + * + * @return column num in result set metadata. + */ +int tsfile_result_set_metadata_get_column_num(ResultSetMetaData result_set); // Desc table schema. -TableSchema tsfile_reader_get_table_schema(TsFileReader reader, - const char* table_name); -DeviceSchema tsfile_reader_get_device_schema(TsFileReader reader, - const char* device_id); +// TableSchema tsfile_reader_get_table_schema(TsFileReader reader, +// const char* table_name); +// DeviceSchema tsfile_reader_get_device_schema(TsFileReader reader, +// const char* device_id); TableSchema* tsfile_reader_get_all_table_schemas(TsFileReader reader, - uint32_t* schema_num); + uint32_t* size); // Close and free resource. void free_tsfile_ts_record(TsRecord* record); diff --git a/cpp/test/cwrapper/cwrapper_test.cc b/cpp/test/cwrapper/cwrapper_test.cc index 394063a0..85429af7 100644 --- a/cpp/test/cwrapper/cwrapper_test.cc +++ b/cpp/test/cwrapper/cwrapper_test.cc @@ -19,6 +19,7 @@ #include <gtest/gtest.h> #include <unistd.h> extern "C" { +#include "cwrapper/errno_define.h" #include "cwrapper/tsfile_cwrapper.h" } @@ -29,119 +30,102 @@ using namespace common; namespace cwrapper { class CWrapperTest : public testing::Test {}; -TEST_F(CWrapperTest, RegisterTimeSeries) { - ERRNO code = 0; - char* temperature = strdup("temperature"); - TimeseriesSchema ts_schema{temperature, TS_DATATYPE_INT32, - TS_ENCODING_PLAIN, TS_COMPRESSION_UNCOMPRESSED}; - remove("cwrapper_register_timeseries.tsfile"); - TsFileWriter writer = tsfile_writer_new("cwrapper_register_timeseries.tsfile", &code); - ASSERT_EQ(code, 0); - code = tsfile_writer_register_timeseries(writer, "device1", &ts_schema); - ASSERT_EQ(code, 0); - free(temperature); - tsfile_writer_close(writer); -} +// TEST_F(CWrapperTest, RegisterTimeSeries) { +// ERRNO code = 0; +// char* temperature = strdup("temperature"); +// TimeseriesSchema ts_schema{temperature, TS_DATATYPE_INT32, +// TS_ENCODING_PLAIN, +// TS_COMPRESSION_UNCOMPRESSED}; +// remove("cwrapper_register_timeseries.tsfile"); +// TsFileWriter writer = +// tsfile_writer_new("cwrapper_register_timeseries.tsfile", &code); +// ASSERT_EQ(code, 0); +// code = tsfile_writer_register_timeseries(writer, "device1", &ts_schema); +// ASSERT_EQ(code, 0); +// free(temperature); +// tsfile_writer_close(writer); +// } TEST_F(CWrapperTest, WriterFlushTabletAndReadData) { ERRNO code = 0; - const int device_num = 50; - const int measurement_num = 50; - DeviceSchema device_schema[50]; + const int column_num = 10; remove("cwrapper_write_flush_and_read.tsfile"); - TsFileWriter writer = tsfile_writer_new("cwrapper_write_flush_and_read.tsfile", &code); - ASSERT_EQ(code, 0); - for (int i = 0; i < device_num; i++) { - char* device_name = strdup(("device" + std::to_string(i)).c_str()); - device_schema[i].device_name = device_name; - device_schema[i].timeseries_num = measurement_num; - device_schema[i].timeseries_schema = (TimeseriesSchema*)malloc( - sizeof(TimeseriesSchema) * measurement_num); - for (int j = 0; j < measurement_num; j++) { - TimeseriesSchema* schema = device_schema[i].timeseries_schema + j; - schema->timeseries_name = - strdup(("measurement" + std::to_string(j)).c_str()); - schema->compression = TS_COMPRESSION_UNCOMPRESSED; - schema->data_type = TS_DATATYPE_INT64; - schema->encoding = TS_ENCODING_PLAIN; - } - code = tsfile_writer_register_device(writer, &device_schema[i]); - ASSERT_EQ(code, 0); - free_device_schema(device_schema[i]); + TableSchema schema; + schema.table_name = "table1"; + schema.column_num = column_num; + schema.column_schemas = + static_cast<ColumnSchema*>(malloc(column_num * sizeof(ColumnSchema))); + schema.column_schemas[0] = + ColumnSchema{"id1", TS_DATATYPE_STRING, TS_COMPRESSION_UNCOMPRESSED, + TS_ENCODING_PLAIN, TAG}; + schema.column_schemas[1] = + ColumnSchema{"id2", TS_DATATYPE_STRING, TS_COMPRESSION_UNCOMPRESSED, + TS_ENCODING_PLAIN, TAG}; + for (int i = 2; i < column_num; i++) { + schema.column_schemas[i] = ColumnSchema{ + strdup(("s" + std::to_string(i)).c_str()), TS_DATATYPE_INT32, + TS_COMPRESSION_UNCOMPRESSED, TS_ENCODING_PLAIN, TAG}; + } + TsFileWriter writer = tsfile_writer_new( + "cwrapper_write_flush_and_read.tsfile", &schema, &code); + ASSERT_EQ(code, RET_OK); + + for (int i = 2; i < column_num; i++) { + free(schema.column_schemas[i].column_name); } + free(schema.column_schemas); + + int max_rows = 100; - for (int i = 0; i < device_num; i++) { - char* device_name = strdup(("device" + std::to_string(i)).c_str()); - char** measurements_name = - static_cast<char**>(malloc(measurement_num * sizeof(char*))); - TSDataType* data_types = static_cast<TSDataType*>( - malloc(sizeof(TSDataType) * measurement_num)); - for (int j = 0; j < measurement_num; j++) { - measurements_name[j] = - strdup(("measurement" + std::to_string(j)).c_str()); - data_types[j] = TS_DATATYPE_INT64; - } - Tablet tablet = - tablet_new_with_device(device_name, measurements_name, data_types, - measurement_num, max_rows); - free(device_name); - free(data_types); - for (int j = 0; j < measurement_num; j++) { - free(measurements_name[j]); - } - free(measurements_name); - for (int j = 0; j < measurement_num; j++) { - for (int row = 0; row < max_rows; row++) { - tablet_add_timestamp(tablet, row, 16225600 + row); - } - for (int row = 0; row < max_rows; row++) { - tablet_add_value_by_index_int64_t( - tablet, row, j, static_cast<int64_t>(row + j)); - } - } - code = tsfile_writer_write_tablet(writer, tablet); + char** column_names = + static_cast<char**>(malloc(column_num * sizeof(char*))); + TSDataType* data_types = + static_cast<TSDataType*>(malloc(sizeof(TSDataType) * column_num)); + + column_names[0] = strdup(std::string("id1").c_str()); + column_names[1] = strdup(std::string("id2").c_str()); + for (int i = 2; i < column_num; i++) { + column_names[i] = strdup(("s" + std::to_string(i)).c_str()); + data_types[i] = TS_DATATYPE_INT32; + } + data_types[0] = TS_DATATYPE_STRING; + data_types[1] = TS_DATATYPE_STRING; + Tablet tablet = tablet_new(column_names, data_types, column_num, max_rows); + + for (int i = 0; i < max_rows; i++) { + code = tablet_add_timestamp(tablet, i, static_cast<Timestamp>(i * 10)); + ASSERT_EQ(code, 0); + code = tablet_add_value_by_index_string(tablet, i, 0, "device"); ASSERT_EQ(code, 0); - free_tablet(&tablet); + code = tablet_add_value_by_index_string( + tablet, i, 1, std::string("sensor" + std::to_string(i)).c_str()); + ASSERT_EQ(code, 0); + for (int j = 2; j < column_num; j++) { + code = tablet_add_value_by_index_int32_t( + tablet, i, j, static_cast<int32_t>(i * 5)); + ASSERT_EQ(code, 0); + } } - ASSERT_EQ(tsfile_writer_flush_data(writer), 0); + code = tsfile_writer_write(writer, tablet); + ASSERT_EQ(code, RET_OK); ASSERT_EQ(tsfile_writer_close(writer), 0); - TsFileReader reader = tsfile_reader_new("cwrapper_write_flush_and_read.tsfile", &code); + TsFileReader reader = + tsfile_reader_new("cwrapper_write_flush_and_read.tsfile", &code); ASSERT_EQ(code, 0); - char** sensor_list = - static_cast<char**>(malloc(measurement_num * sizeof(char*))); - for (int i = 0; i < measurement_num; i++) { - sensor_list[i] = strdup(("measurement" + std::to_string(i)).c_str()); - } + char** sensor_list = static_cast<char**>(malloc(4 * sizeof(char*))); + sensor_list[0] = "id1"; + sensor_list[1] = "id2"; + sensor_list[2] = "s1"; + sensor_list[3] = "s2"; ResultSet result_set = - tsfile_reader_query_device(reader,"device0", sensor_list, measurement_num, 16225600, - 16225600 + max_rows - 1); + tsfile_query_table(reader, "table1", sensor_list, 4, 0, 100); ResultSetMetaData metadata = tsfile_result_set_get_metadata(result_set); - ASSERT_EQ(metadata.column_num, measurement_num); - ASSERT_EQ(std::string(metadata.column_names[4]), - std::string("device0.measurement4")); - ASSERT_EQ(metadata.data_types[9], TS_DATATYPE_INT64); - for (int i = 0; i < measurement_num - 1; i++) { - ASSERT_TRUE(tsfile_result_set_has_next(result_set)); - ASSERT_FALSE(tsfile_result_set_is_null_by_index(result_set, i)); - ASSERT_EQ(tsfile_result_set_get_value_by_index_int64_t(result_set, i + 1), - i * 2); - ASSERT_EQ(tsfile_result_set_get_value_by_name_int64_t( - result_set, - std::string("measurement" + std::to_string(i)).c_str()), - i * 2); - } - free_tsfile_result_set(&result_set); - free_result_set_meta_data(metadata); - for (int i = 0; i < measurement_num; i++) { - free(sensor_list[i]); - } - free(sensor_list); - tsfile_reader_close(reader); - // DeviceSchema schema = tsfile_reader_get_device_schema(reader, - // "device4"); ASSERT_EQ(schema.timeseries_num, 1); - // ASSERT_EQ(schema.timeseries_schema->name, std::string("measurement4")); + ASSERT_EQ(metadata.column_num, 4); + ASSERT_EQ(std::string(metadata.column_names[3]), + std::string("s2")); + ASSERT_EQ(metadata.data_types[3], TS_DATATYPE_INT32); } } // namespace cwrapper \ No newline at end of file