Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cpp/src/common/constant/tsfile_constant.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ static const std::string BACK_QUOTE_STRING = "`";
static const std::string DOUBLE_BACK_QUOTE_STRING = "``";

static const unsigned char TIME_COLUMN_MASK = 0x80;
static const std::string TIME_COLUMN_NAME = "time";
static const unsigned char VALUE_COLUMN_MASK = 0x40;

static const std::string TIME_COLUMN_ID = "";
static const int NO_STR_TO_READ = -1;

static const std::regex IDENTIFIER_PATTERN("([a-zA-Z0-9_\\u2E80-\\u9FFF]+)");
static const std::regex NODE_NAME_PATTERN(
"(\\*{0,2}[a-zA-Z0-9_\\u2E80-\\u9FFF]+\\*{0,2})");
static const int DEFAULT_SEGMENT_NUM_FOR_TABLE_NAME = 3;

} // namespace storage

#endif
2 changes: 1 addition & 1 deletion cpp/src/common/global.cc
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ int init_common() {
g_time_column_schema.data_type_ = INT64;
g_time_column_schema.encoding_ = PLAIN;
g_time_column_schema.compression_ = UNCOMPRESSED;
g_time_column_schema.column_name_ = std::string("time");
g_time_column_schema.column_name_ = storage::TIME_COLUMN_NAME;
return ret;
}

Expand Down
9 changes: 9 additions & 0 deletions cpp/src/common/tsblock/tuple_desc.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ class TupleDesc {
return column_list_[index].column_category_;
}

FORCE_INLINE int get_time_column_index() const {
for (uint32_t i = 0; i < column_list_.size(); i++) {
if (column_list_[i].get_column_category() == ColumnCategory::TIME) {
return i;
}
}
return -1;
}
Comment on lines +79 to +86
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Save the index to avoid iteration every time.


FORCE_INLINE std::string get_column_name(uint32_t index) {
return column_list_[index].column_name_;
}
Expand Down
1 change: 0 additions & 1 deletion cpp/src/cwrapper/tsfile_cwrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ TsFileWriter tsfile_writer_new(WriteFile file, TableSchema* schema,
*err_code = common::E_INVALID_SCHEMA;
return nullptr;
}

column_schemas.emplace_back(
cur_schema.column_name,
static_cast<common::TSDataType>(cur_schema.data_type),
Expand Down
7 changes: 6 additions & 1 deletion cpp/src/cwrapper/tsfile_cwrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,12 @@ typedef enum {
TS_COMPRESSION_INVALID = 255
} CompressionType;

typedef enum column_category { TAG = 0, FIELD = 1 } ColumnCategory;
typedef enum column_category {
TAG = 0,
FIELD = 1,
ATTRIBUTE = 2,
TIME = 3
} ColumnCategory;

typedef struct column_schema {
char* column_name;
Expand Down
8 changes: 8 additions & 0 deletions cpp/src/reader/block/single_device_tsblock_reader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,14 @@ int SingleDeviceTsBlockReader::fill_measurements(
}
col_appenders_[time_column_index_]->append((const char*)&next_time_,
sizeof(next_time_));
int time_in_query_index = tuple_desc_.get_time_column_index();
if (time_in_query_index != -1) {
if (!col_appenders_[time_in_query_index]->add_row()) {
assert(false);
}
col_appenders_[time_in_query_index]->append(
(const char*)&next_time_, sizeof(next_time_));
}
for (auto& column_context : column_contexts) {
column_context->fill_into(col_appenders_);
if (RET_FAIL(advance_column(column_context))) {
Expand Down
11 changes: 10 additions & 1 deletion cpp/src/reader/column_mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ class ColumnMapping {

if (column_category == common::ColumnCategory::TAG) {
tag_columns_.insert(column_name);
} else {
} else if (column_category == common::ColumnCategory::FIELD) {
field_columns_.insert(column_name);
} else if (column_category == common::ColumnCategory::TIME) {
time_column_ = column_name;
}

return common::E_OK;
Expand All @@ -64,6 +66,10 @@ class ColumnMapping {
return field_columns_.find(column_name) != field_columns_.end();
}

bool is_time(const std::string& column_name) const {
return time_column_ == column_name;
}

const std::unordered_set<std::string>& get_id_columns() const {
return tag_columns_;
}
Expand All @@ -72,8 +78,11 @@ class ColumnMapping {
return field_columns_;
}

const std::string get_time_column() const { return time_column_; }

private:
std::unordered_map<std::string, std::vector<int>> column_pos_map;
std::string time_column_;
std::unordered_set<std::string> tag_columns_;
std::unordered_set<std::string> field_columns_;
};
Expand Down
11 changes: 6 additions & 5 deletions cpp/src/reader/table_query_executor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,10 @@ int TableQueryExecutor::query(const std::string& table_name,
}
// column_mapping.add(*measurement_filter);

auto device_task_iterator = std::unique_ptr<DeviceTaskIterator>(
new DeviceTaskIterator(columns, table_root, column_mapping,
meta_data_querier_, id_filter, table_schema));
auto device_task_iterator =
std::unique_ptr<DeviceTaskIterator>(new DeviceTaskIterator(
lower_case_column_names, table_root, column_mapping,
meta_data_querier_, id_filter, table_schema));

std::unique_ptr<TsBlockReader> tsblock_reader;
switch (table_query_ordering_) {
Expand All @@ -82,8 +83,8 @@ int TableQueryExecutor::query(const std::string& table_name,
ret = common::E_UNSUPPORTED_ORDER;
}
assert(tsblock_reader != nullptr);
ret_qds =
new TableResultSet(std::move(tsblock_reader), columns, data_types);
ret_qds = new TableResultSet(std::move(tsblock_reader),
lower_case_column_names, data_types);
return ret;
}

Expand Down
4 changes: 3 additions & 1 deletion cpp/src/utils/db_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ namespace common {
extern TSEncoding get_value_encoder(TSDataType data_type);
extern CompressionType get_default_compressor();

// TODO: remove this.
typedef struct FileID {
int64_t seq_; // timestamp when create
int32_t version_;
Expand Down Expand Up @@ -64,6 +65,7 @@ typedef struct FileID {
#endif
} FileID;

// TODO: remove this.
typedef uint16_t NodeID;
struct TsID {
NodeID db_nid_;
Expand Down Expand Up @@ -157,7 +159,7 @@ struct TsID {
* This enumeration class defines the supported categories for columns within a
* table schema, distinguishing between tag and field columns.
*/
enum class ColumnCategory { TAG = 0, FIELD = 1 };
enum class ColumnCategory { TAG = 0, FIELD = 1, ATTRIBUTE = 2, TIME = 3 };

/**
* @brief Represents the schema information for a single column.
Expand Down
81 changes: 81 additions & 0 deletions cpp/test/reader/table_view/tsfile_reader_table_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -707,3 +707,84 @@ TEST_F(TsFileTableReaderTest, TestNullInTable4) {
ASSERT_EQ(line, max_rows);
});
}

TEST_F(TsFileTableReaderTest, TestTimeColumnReader) {
std::vector<common::ColumnSchema> column_schemas;
column_schemas.emplace_back("s0", TSDataType::INT64,
CompressionType::UNCOMPRESSED,
TSEncoding::PLAIN, ColumnCategory::FIELD);
column_schemas.emplace_back("S1", TSDataType::DOUBLE,
CompressionType::UNCOMPRESSED,
TSEncoding::PLAIN, ColumnCategory::FIELD);
// No need to manually insert data into the time column.
column_schemas.emplace_back("TIME_D", TSDataType::TIMESTAMP,
CompressionType::UNCOMPRESSED,
TSEncoding::PLAIN, ColumnCategory::TIME);

TableSchema table_schema("testTableTime", column_schemas);
auto tsfile_table_writer_ =
std::make_shared<TsFileTableWriter>(&write_file_, &table_schema);

const int num_rows = 20;
const int64_t base_time = 1000;
storage::Tablet tablet(table_schema.get_table_name(), {"s0", "s1"},
{TSDataType::INT64, TSDataType::DOUBLE},
{ColumnCategory::FIELD, ColumnCategory::FIELD},
num_rows);

for (int i = 0; i < num_rows; i++) {
int64_t t = base_time + i;
tablet.add_timestamp(i, t);
tablet.add_value(i, 0, static_cast<int64_t>(i * 10));
tablet.add_value(i, 1, static_cast<double>(i * 1.5));
}

ASSERT_EQ(tsfile_table_writer_->write_table(tablet), common::E_OK);
ASSERT_EQ(tsfile_table_writer_->flush(), common::E_OK);
ASSERT_EQ(tsfile_table_writer_->close(), common::E_OK);

storage::TsFileReader reader;
int ret = reader.open(file_name_);
ASSERT_EQ(ret, common::E_OK);

ResultSet* tmp_result_set = nullptr;
ret = reader.query(table_schema.get_table_name(), {"s0", "s1", "TIME_D"}, 0,
1000000000000, tmp_result_set);
ASSERT_EQ(ret, common::E_OK);
ASSERT_NE(tmp_result_set, nullptr);

auto* table_result_set = dynamic_cast<TableResultSet*>(tmp_result_set);
ASSERT_NE(table_result_set, nullptr);

auto result_set_metadata = table_result_set->get_metadata();
ASSERT_EQ(result_set_metadata->get_column_count(),
4); // time + s0 + s1 + TIME_D
ASSERT_EQ(result_set_metadata->get_column_name(1), "time");
ASSERT_EQ(result_set_metadata->get_column_type(1), TSDataType::INT64);
ASSERT_EQ(result_set_metadata->get_column_name(2), "s0");
ASSERT_EQ(result_set_metadata->get_column_type(2), TSDataType::INT64);
ASSERT_EQ(result_set_metadata->get_column_name(3), "s1");
ASSERT_EQ(result_set_metadata->get_column_type(3), TSDataType::DOUBLE);
ASSERT_EQ(result_set_metadata->get_column_name(4), "time_d");
ASSERT_EQ(result_set_metadata->get_column_type(4), TSDataType::TIMESTAMP);

bool has_next = false;
int row_count = 0;
while (IS_SUCC(table_result_set->next(has_next)) && has_next) {
int64_t row_time = base_time + row_count;
// Column 1 is built-in time
ASSERT_EQ(table_result_set->get_value<int64_t>(1), row_time);
// s0, s1
ASSERT_EQ(table_result_set->get_value<int64_t>(2), row_count * 10);
ASSERT_DOUBLE_EQ(table_result_set->get_value<double>(3),
static_cast<double>(row_count * 1.5));
// time_d
ASSERT_EQ(table_result_set->get_value<int64_t>("TIME_D"), row_time);
ASSERT_EQ(table_result_set->get_value<int64_t>(4), row_time);
row_count++;
}
ASSERT_EQ(row_count, num_rows);

reader.destroy_query_data_set(table_result_set);
ASSERT_EQ(reader.close(), common::E_OK);
}
2 changes: 1 addition & 1 deletion cpp/test/writer/table_view/tsfile_writer_table_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ TEST_F(TsFileWriterTableTest, WriteAndReadSimple) {
ASSERT_EQ(ret_value, 0);
auto* table_result_set = (TableResultSet*)ret;
auto metadata = ret->get_metadata();
ASSERT_EQ(metadata->get_column_name(column_names.size() + 1), "VALUE");
ASSERT_EQ(metadata->get_column_name(column_names.size() + 1), "value");
bool has_next = false;
int cur_line = 0;
while (IS_SUCC(table_result_set->next(has_next)) && has_next) {
Expand Down
52 changes: 51 additions & 1 deletion python/tests/resources/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,4 +282,54 @@ IoTDB:test> select * from test;
|2025-10-10T22:21:19.000+08:00| b| c|1069|7.9|v69|1970-01-01T08:00:01.069+08:00| 79|16.9|2024-12-18|text69|
+-----------------------------+--+--+----+---+---+-----------------------------+----+----+----------+------+
Total line number = 40
```
```

In `table_with_time_column.tsfile`

```
IoTDB:mydb> select * from table2;
+-----------------------------+---------+-----------+--------+
| id|region_id|temperature|humidity|
+-----------------------------+---------+-----------+--------+
|2026-02-10T21:11:35.888+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:36.807+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:37.233+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:37.471+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:37.695+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:37.910+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:38.148+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:38.385+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:38.599+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:38.853+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:39.086+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:39.327+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:39.558+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:39.794+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:40.017+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:40.262+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:40.492+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:40.729+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:40.976+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:41.243+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:41.494+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:41.734+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:42.040+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:42.333+08:00| loc| 0.1| 0.1|
|2026-02-10T21:11:43.005+08:00| loc| 0.1| 0.1|
+-----------------------------+---------+-----------+--------+
Total line number = 25
It costs 0.042s
IoTDB:mydb> describe table2
+-----------+---------+--------+
| ColumnName| DataType|Category|
+-----------+---------+--------+
| id|TIMESTAMP| TIME|
| region_id| STRING| TAG|
|temperature| FLOAT| FIELD|
| humidity| DOUBLE| FIELD|
+-----------+---------+--------+
Total line number = 4
It costs 0.065s
IoTDB:mydb>
```

Binary file added python/tests/resources/table_with_time_column.tsfile
Binary file not shown.
2 changes: 1 addition & 1 deletion python/tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#
import numpy as np
import pytest
from tsfile import schema, Field
from tsfile import Field
from tsfile import Tablet
from tsfile.constants import *
from tsfile.schema import *
Expand Down
Loading
Loading