Interface definition - C

Schema

typedef enum {
    TS_DATATYPE_BOOLEAN = 0,
    TS_DATATYPE_INT32 = 1,
    TS_DATATYPE_INT64 = 2,
    TS_DATATYPE_FLOAT = 3,
    TS_DATATYPE_DOUBLE = 4,
    TS_DATATYPE_TEXT = 5,
    TS_DATATYPE_VECTOR = 6,
    TS_DATATYPE_TIMESTAMP = 8,
    TS_DATATYPE_DATE = 9,
    TS_DATATYPE_BLOB = 10,
    TS_DATATYPE_STRING = 11,
    TS_DATATYPE_NULL_TYPE = 254,
    TS_DATATYPE_INVALID = 255
} TSDataType;

// Value encoding.
typedef enum {
    TS_ENCODING_PLAIN = 0,
    TS_ENCODING_DICTIONARY = 1,
    TS_ENCODING_RLE = 2,
    TS_ENCODING_TS_2DIFF = 4,
    TS_ENCODING_GORILLA = 8,
    TS_ENCODING_ZIGZAG = 9,
    TS_ENCODING_SPRINTZ = 12,
    TS_ENCODING_INVALID = 255
} TSEncoding;

// Compression type. LZ4 is the default.
typedef enum {
    TS_COMPRESSION_UNCOMPRESSED = 0,
    TS_COMPRESSION_SNAPPY = 1,
    TS_COMPRESSION_GZIP = 2,
    TS_COMPRESSION_LZO = 3,
    TS_COMPRESSION_LZ4 = 7,
    TS_COMPRESSION_INVALID = 255
} CompressionType;

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

// ColumnSchema: Represents the schema of a single column,
// including its name, data type, and category.
// On write, encoding/compression for columns follow the global defaults
// (see "Configuration" below).
typedef struct column_schema {
    char* column_name;
    TSDataType data_type;
    ColumnCategory column_category;
} ColumnSchema;

// TableSchema: Defines the schema of a table, 
// including its name and a list of column schemas.
typedef struct table_schema {
    char* table_name;
    ColumnSchema* column_schemas;
    int column_num;
} TableSchema;

// ResultSetMetaData: Contains metadata for a result set, 
// such as column names and their data types.
typedef struct result_set_meta_data {
    char** column_names;
    TSDataType* data_types;
    int column_num;
} ResultSetMetaData;

typedef struct arrow_schema ArrowSchema;
typedef struct arrow_array ArrowArray;

typedef struct TsFileStatisticBase {
    bool has_statistic;
    TSDataType type;
    int32_t row_count;
    int64_t start_time;
    int64_t end_time;
} TsFileStatisticBase;

typedef struct TsFileBoolStatistic { TsFileStatisticBase base; double sum; bool first_bool; bool last_bool; } TsFileBoolStatistic;
typedef struct TsFileIntStatistic { TsFileStatisticBase base; double sum; int64_t min_int64; int64_t max_int64; int64_t first_int64; int64_t last_int64; } TsFileIntStatistic;
typedef struct TsFileFloatStatistic { TsFileStatisticBase base; double sum; double min_float64; double max_float64; double first_float64; double last_float64; } TsFileFloatStatistic;
typedef struct TsFileStringStatistic { TsFileStatisticBase base; char* str_min; char* str_max; char* str_first; char* str_last; } TsFileStringStatistic;
typedef struct TsFileTextStatistic { TsFileStatisticBase base; char* str_first; char* str_last; } TsFileTextStatistic;

typedef union TimeseriesStatisticUnion {
    TsFileBoolStatistic bool_s;
    TsFileIntStatistic int_s;
    TsFileFloatStatistic float_s;
    TsFileStringStatistic string_s;
    TsFileTextStatistic text_s;
} TimeseriesStatisticUnion;

typedef struct TimeseriesStatistic {
    TimeseriesStatisticUnion u;
} TimeseriesStatistic;

#define tsfile_statistic_base(s) ((TsFileStatisticBase*)&(s)->u)

ColumnSchema does not carry encoding/compression: on write, columns follow the global defaults (see Configuration); on read, each column is decoded with the file's actual settings. The encoding and compression constants listed above are the values accepted by the current writer/configuration path.

TimeseriesStatistic is a tagged union in tsfile_cwrapper.h. Read common fields through tsfile_statistic_base(&statistic) and then use the active typed member (int_s, float_s, bool_s, string_s, or text_s) according to the statistic data type.

Write Interface

TsFile WriteFile Create/Close

/**
 * @brief Creates a file for writing.
 *
 * @param pathname     Target file to create.
 * @param err_code     [out] RET_OK(0), or error code in errno_define_c.h.
 *
 * @return WriteFile Valid handle on success.
 *
 * @note Call free_write_file() to release resources.
 * @note Before call free_write_file(), make sure TsFileWriter has been closed.
 */

WriteFile write_file_new(const char* pathname, ERRNO* err_code);

void free_write_file(WriteFile* write_file);

TsFile Writer Create/Close

When creating a TsFile Writer, you specify a WriteFile and a TableSchema. As you write, data is buffered in memory and automatically flushed to disk once the buffered size exceeds memory_threshold bytes. tsfile_writer_new uses the default (128 MB); tsfile_writer_new_with_memory_threshold lets you override it — a larger value buffers more before flushing (more memory, larger chunk groups), a smaller value flushes more often.

/**
 * @brief Creates a TsFileWriter for writing a TsFile.
 *
 * @param file     Target file where the table data will be written.
 * @param schema       Table schema definition.
 *                     - Ownership: Should be freed by the caller.
 * @param err_code     [out] RET_OK(0), or error code in errno_define_c.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 TsFileWriter for writing a TsFile.
 *
 * @param file     Target file where the table data will be written.
 * @param schema       Table schema definition.
 *                     - Ownership: Should be freed by the caller.
 * @param memory_threshold When the size of written data exceeds
 * this value, the data will be automatically flushed to the disk. 
 * @param err_code     [out] RET_OK(0), or error code in errno_define_c.h.
 *
 * @return TsFileWriter Valid handle on success, NULL on failure.
 *
 * @note Call tsfile_writer_close() to release resources.
 */
TsFileWriter tsfile_writer_new_with_memory_threshold(WriteFile file,
                                                     TableSchema* schema,
                                                     uint64_t memory_threshold,
                                                     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 - RET_OK(0) on success, or error code in errno_define_c.h.
 */
ERRNO tsfile_writer_close(TsFileWriter writer);

Tablet Create/Close/Insert data

You can use Tablet to insert data into TsFile in batches, and you need to release the space occupied by the Tablet after use.

/**
 * @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 - RET_OK(0) or error code in errno_define_c.h.
 */
ERRNO tablet_add_timestamp(Tablet tablet, uint32_t row_index,
                           Timestamp timestamp);
                           
/**
 * @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_with_len(Tablet tablet,
                                               uint32_t row_index,
                                               const char* column_name,
                                               const char* value,
                                               int value_len);

 // Supports multiple data types
ERRNO tablet_add_value_by_name_int32_t(Tablet tablet, uint32_t row_index,
                                      const char* column_name,
                                      int32_t value);
ERRNO tablet_add_value_by_name_int64_t(Tablet tablet, uint32_t row_index,
                                      const char* column_name,
                                      int64_t value);

ERRNO tablet_add_value_by_name_double(Tablet tablet, uint32_t row_index,
                                      const char* column_name,
                                      double value);

ERRNO tablet_add_value_by_name_float(Tablet tablet, uint32_t row_index,
                                      const char* column_name,
                                      float value);

ERRNO tablet_add_value_by_name_bool(Tablet tablet, uint32_t row_index,
                                      const char* column_name,
                                      bool value);


/**
 * @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_with_len(Tablet tablet,
                                                uint32_t row_index,
                                                uint32_t column_index,
                                                const char* value,
                                                int value_len);


// Supports multiple data types
ERRNO tablet_add_value_by_index_int32_t(Tablet tablet, uint32_t row_index,
                                      uint32_t column_index,
                                      int32_t value);
ERRNO tablet_add_value_by_index_int64_t(Tablet tablet, uint32_t row_index,
                                      uint32_t column_index,
                                      int64_t value);

ERRNO tablet_add_value_by_index_double(Tablet tablet, uint32_t row_index,
                                      uint32_t column_index,
                                      double value);

ERRNO tablet_add_value_by_index_float(Tablet tablet, uint32_t row_index,
                                      uint32_t column_index,
                                      float value);

ERRNO tablet_add_value_by_index_bool(Tablet tablet, uint32_t row_index,
                                      uint32_t column_index,
                                      bool value);

                                       
void free_tablet(Tablet* tablet);

Write Tablet into TsFile

/**
 * @brief Writes data from a Tablet to the TsFile.
 *
 * @param writer [in] Valid TsFileWriter handle.
 * @param tablet [in] Tablet containing data. Should be freed after successful
 * writing.
 * @return ERRNO - RET_OK(0), or error code in errno_define_c.h.
 *
 */

ERRNO tsfile_writer_write(TsFileWriter writer, Tablet tablet);

Configuration (encoding & compression)

Columns are stored with the global default encoding and compression for their data type (a ColumnSchema does not carry codec settings). Change those defaults before creating a writer with the functions below.

Each setter returns RET_OK (0) on success, or RET_NOT_SUPPORT (40) for an unsupported data-type/encoding or compression combination.

/* Default value encoding per data type, and default compression. */
int     set_datatype_encoding(uint8_t data_type, uint8_t encoding);
int     set_global_compression(uint8_t compression);
uint8_t get_datatype_encoding(uint8_t data_type);
uint8_t get_global_compression();

/* Time column (the time data type is fixed to INT64). */
int     set_global_time_encoding(uint8_t encoding);
int     set_global_time_compression(uint8_t compression);
uint8_t get_global_time_encoding();
uint8_t get_global_time_compression();

Allowed encodings per data type, and the default used when you do not change it:

Data typeAllowed encodingsDefault
BOOLEANPLAINPLAIN
INT32, INT64, DATEPLAIN, TS_2DIFF, GORILLA, ZIGZAG, RLE, SPRINTZTS_2DIFF
FLOAT, DOUBLEPLAIN, TS_2DIFF, GORILLA, SPRINTZGORILLA
STRING, TEXTPLAIN, DICTIONARYPLAIN

The time column uses the global time configuration and accepts PLAIN, TS_2DIFF, GORILLA, ZIGZAG, RLE, or SPRINTZ.

Compression applies to any data type: UNCOMPRESSED, SNAPPY, GZIP, LZO, or LZ4 (default LZ4).

// e.g. write every column with LZ4 compression
ERRNO code = set_global_compression(TS_COMPRESSION_LZ4);
if (code != RET_OK) { /* handle unsupported value */ }

Read Interface

TsFile Reader Create/Close

/**
 * @brief Creates a TsFileReader for reading a TsFile.
 *
 * @param pathname     Source TsFiles path. Must be a valid path.
 * @param err_code     RET_OK(0), or error code in errno_define_c.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 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 - RET_OK(0) on success, or error code in errno_define_c.h.
 */
ERRNO tsfile_reader_close(TsFileReader reader);

Query table/get next


/** * @brief Query data from the specific table and columns within time range. * * @param reader [in] Valid TsFileReader handle from tsfile_reader_new(). * @param table_name [in] Target table name. Must exist in the TsFile. * @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. * @param err_code [out] RET_OK(0) on success, or error code in errno_define_c.h. * @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, ERRNO* err_code); /** * @brief Check and fetch the next row in the ResultSet. * * @param result_set [in] Valid ResultSet handle. * @param error_code RET_OK(0) on success, or error code in errno_define_c.h. * @return bool - true: Row available, false: End of data or error. */ bool tsfile_result_set_next(ResultSet result_set, ERRNO* error_code); /** * @brief Free Result set * * @param result_set [in] Valid ResultSet handle ptr. */ void free_tsfile_result_set(ResultSet* result_set);

Tree queries

/**
 * @brief Query tree-model data by measurement names within a time range.
 */
ResultSet tsfile_query_table_on_tree(TsFileReader reader, char** columns,
                                     uint32_t column_num, Timestamp start_time,
                                     Timestamp end_time, ERRNO* err_code);

/**
 * @brief Query tree-model data by row with offset/limit.
 *
 * @param device_ids Array of device identifiers.
 * @param measurement_names Array of measurement names.
 * @param offset Leading rows to skip (>= 0).
 * @param limit Max rows to return; < 0 means unlimited.
 */
ResultSet tsfile_reader_query_tree_by_row(TsFileReader reader,
                                          char** device_ids, int device_ids_len,
                                          char** measurement_names,
                                          int measurement_names_len, int offset,
                                          int limit, ERRNO* err_code);

Filtering by tag

TAG columns form the device identity (a joint primary key) — their values are what distinguish one device from another within a table. A tag filter restricts a query to the devices whose TAG values match a predicate, so you read only the devices you care about. Build a filter from the reader, pass it to one of the table-query functions below, then release it with tsfile_tag_filter_free().

// Opaque handle to a tag filter. Build it with the functions below.
typedef void* TagFilterHandle;

// Comparison operators for a single-column TAG predicate.
typedef enum {
    TAG_FILTER_EQ = 0,          // column == value
    TAG_FILTER_NEQ = 1,         // column != value
    TAG_FILTER_LT = 2,          // column <  value
    TAG_FILTER_LTEQ = 3,        // column <= value
    TAG_FILTER_GT = 4,          // column >  value
    TAG_FILTER_GTEQ = 5,        // column >= value
    TAG_FILTER_REGEXP = 6,      // column matches the regex value
    TAG_FILTER_NOT_REGEXP = 7,  // column does not match the regex value
    TAG_FILTER_IS_NULL = 8,     // column is null
    TAG_FILTER_IS_NOT_NULL = 9, // column is not null
} TagFilterOp;

/**
 * @brief Create a single-column TAG predicate: `<column_name> <op> <value>`.
 *
 * @param reader      [in] Valid TsFileReader handle.
 * @param table_name  [in] Table whose schema defines the TAG columns.
 * @param column_name [in] Name of the TAG column to filter on.
 * @param value       [in] Comparison value (ignored for IS NULL / IS NOT NULL).
 * @param op          [in] Comparison operator (TagFilterOp).
 * @param err_code    [out] RET_OK(0) on success, or error code in errno_define_c.h.
 * @return TagFilterHandle on success; NULL on failure.
 */
TagFilterHandle tsfile_tag_filter_create(TsFileReader reader,
                                         const char* table_name,
                                         const char* column_name,
                                         const char* value, TagFilterOp op,
                                         ERRNO* err_code);

/**
 * @brief Create a range predicate: lower <= column <= upper
 *        (pass is_not = true for NOT BETWEEN).
 */
TagFilterHandle tsfile_tag_filter_between(TsFileReader reader,
                                          const char* table_name,
                                          const char* column_name,
                                          const char* lower, const char* upper,
                                          bool is_not, ERRNO* err_code);

// Convenience builders for common single-column predicates.
TagFilterHandle tsfile_tag_filter_eq(TsFileReader reader, const char* table_name,
                                     const char* column_name, const char* value);
TagFilterHandle tsfile_tag_filter_neq(TsFileReader reader, const char* table_name,
                                      const char* column_name, const char* value);
TagFilterHandle tsfile_tag_filter_lt(TsFileReader reader, const char* table_name,
                                     const char* column_name, const char* value);
TagFilterHandle tsfile_tag_filter_lteq(TsFileReader reader, const char* table_name,
                                       const char* column_name, const char* value);
TagFilterHandle tsfile_tag_filter_gt(TsFileReader reader, const char* table_name,
                                     const char* column_name, const char* value);
TagFilterHandle tsfile_tag_filter_gteq(TsFileReader reader, const char* table_name,
                                       const char* column_name, const char* value);

// Combine predicates. AND/OR/NOT take ownership of their children; free the root only.
TagFilterHandle tsfile_tag_filter_and(TagFilterHandle left, TagFilterHandle right);
TagFilterHandle tsfile_tag_filter_or(TagFilterHandle left, TagFilterHandle right);
TagFilterHandle tsfile_tag_filter_not(TagFilterHandle filter);

// Free a tag filter and all of its children.
void tsfile_tag_filter_free(TagFilterHandle filter);

Table queries with tag filter, paging and batching

These query functions accept an optional tag_filter (pass NULL for no filtering) and a batch_size (<= 0 returns rows one by one; > 0 returns a block of that size).

/**
 * @brief Query a table by row, with offset/limit pushdown and an optional tag filter.
 *
 * @param reader           [in] Valid TsFileReader handle.
 * @param table_name       [in] Target table name.
 * @param column_names     [in] Requested column names.
 * @param column_names_len [in] Number of requested columns.
 * @param offset           [in] Leading rows to skip (>= 0).
 * @param limit            [in] Max rows to return; < 0 means unlimited.
 * @param tag_filter       [in] TAG predicate, or NULL for no filtering.
 * @param batch_size       [in] <= 0 row-by-row; > 0 block size.
 * @param err_code         [out] RET_OK(0) on success, or error code.
 * @return ResultSet handle; NULL on failure. Free with free_tsfile_result_set().
 */
ResultSet tsfile_reader_query_table_by_row(
    TsFileReader reader, const char* table_name, char** column_names,
    int column_names_len, int offset, int limit, TagFilterHandle tag_filter,
    int batch_size, ERRNO* err_code);

/**
 * @brief Query a table within a time range, with an optional tag filter and batching.
 *
 * @param batch_size <= 0 row-by-row return; > 0 returns a TsBlock of that size.
 */
ResultSet tsfile_query_table_batch(TsFileReader reader, const char* table_name,
                                   char** columns, uint32_t column_num,
                                   Timestamp start_time, Timestamp end_time,
                                   TagFilterHandle tag_filter, int batch_size,
                                   ERRNO* err_code);

/**
 * @brief Query a table with a tag filter (time range + TAG predicate).
 *
 * @param batch_size <= 0 row-by-row return; > 0 returns a TsBlock of that size.
 */
ResultSet tsfile_query_table_with_tag_filter(
    TsFileReader reader, const char* table_name, char** columns,
    uint32_t column_num, Timestamp start_time, Timestamp end_time,
    TagFilterHandle tag_filter, int batch_size, ERRNO* err_code);

Read batch results as Arrow

Batch query result sets (batch_size > 0) can be fetched as Arrow C Data Interface arrays and schemas. The caller owns the returned Arrow objects and must call their release callbacks when finished.

ERRNO tsfile_result_set_get_next_tsblock_as_arrow(ResultSet result_set,
                                                  ArrowArray* out_array,
                                                  ArrowSchema* out_schema);

Example — read temperature only for devices whose region TAG equals shanghai:

ERRNO ec = RET_OK;
TagFilterHandle f = tsfile_tag_filter_create(
    reader, "weather", "region", "shanghai", TAG_FILTER_EQ, &ec);

char* cols[] = {"temperature"};
ResultSet rs = tsfile_reader_query_table_by_row(
    reader, "weather", cols, 1, /*offset*/ 0, /*limit*/ -1, f, /*batch*/ 0, &ec);

// ... iterate rs with tsfile_result_set_next(), then release:
free_tsfile_result_set(&rs);
tsfile_tag_filter_free(f);

Get Data from result set

/**
 * @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 (1 <= 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);

/**
 * @brief Gets string value from current row by column name.
 * @param result_set [in] valid result set handle.
 * @param column_name [in] the name of the column to be checked.
 * @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);

// Supports multiple data types
bool tsfile_result_set_get_value_by_name_bool(ResultSet result_set, const char* 
                                                column_name);
int32_t tsfile_result_set_get_value_by_name_int32_t(ResultSet result_set, const char* 
                                                column_name);
int64_t tsfile_result_set_get_value_by_name_int64_t(ResultSet result_set, const char* 
                                                column_name);
float tsfile_result_set_get_value_by_name_float(ResultSet result_set, const char* 
                                                column_name);
double tsfile_result_set_get_value_by_name_double(ResultSet result_set, const char* 
                                                column_name);

/**
 * @brief Gets string value from current row by column index.
 * @param result_set [in] valid result set handle.
 * @param column_index [in] the index of the column to be checked (1 <= index <= column_num).
 * @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);

// Supports multiple data types
int32_t tsfile_result_set_get_value_by_index_int32_t(ResultSet result_set, uint32_t 
                                                    column_index);
int64_t tsfile_result_set_get_value_by_index_int64_t(ResultSet result_set, uint32_t 
                                                    column_index);
float tsfile_result_set_get_value_by_index_float(ResultSet result_set, uint32_t 
                                                    column_index);
double tsfile_result_set_get_value_by_index_double(ResultSet result_set, uint32_t 
                                                    column_index);
bool tsfile_result_set_get_value_by_index_bool(ResultSet result_set, uint32_t 
                                                    column_index);

/**
 * @brief Retrieves metadata describing the ResultSet's schema.
 *
 * @param result_set [in] Valid result set handle.
 * @return ResultSetMetaData Metadata handle. Caller should free the
 * ResultSetMataData after usage.
 * @note Before calling this func, check if the result_set is NULL, which
 * may indicates a failed query execution.
 */
ResultSetMetaData tsfile_result_set_get_metadata(ResultSet result_set);

/**
 * @brief Gets column name by index from metadata.
 * @param result_set_meta_data [in] Valid result set handle.
 * @param column_index [in] Column position (1 <= index <= column_num).
 * @return const char* Read-only string. NULL if index invalid.
 */
char* tsfile_result_set_metadata_get_column_name(ResultSetMetaData result_set_meta_data,
                                                 uint32_t column_index);

/**
 * @brief Gets column data type by index from metadata.
 * @param result_set_meta_data [in] Valid result set meta data handle.
 * @param column_index [in] Column position (1 <= index <= column_num).
 * @return TSDataType Returns TS_DATATYPE_INVALID(255) if index invalid.
 */
TSDataType tsfile_result_set_metadata_get_data_type(
    ResultSetMetaData result_set_meta_data, uint32_t column_index);

/**
 * @brief Gets total number of columns in the result schema.
 * @param result_set_meta_data [in] Valid result set meta data handle.
 * @return column num in result set metadata.
 */
int tsfile_result_set_metadata_get_column_num(ResultSetMetaData result_set);

Get Table Schema from TsFile Reader

/**
 * @brief Gets specific table's schema in the tsfile.
 * @param reader [in], valid reader handle.
 * @param table_name [in] Target table name. Must exist in the TsFile.
 * @return TableSchema, contains table and column info.
 * @note Caller should call free_table_schema to free the tableschema.
 */
TableSchema tsfile_reader_get_table_schema(TsFileReader reader,
                                           const char* table_name);
/**
 * @brief Gets all tables' schema in the tsfile.
 * @param size[out] num of tableschema in return ptr.
 * @return TableSchema*, an array of table schema.
 * @note The caller must call free_table_schema() on each array element
 *  and free to deallocate the array pointer.
 */
TableSchema* tsfile_reader_get_all_table_schemas(TsFileReader reader,
                                                 uint32_t* size);

/**
 * @brief Free the tableschema's space.
 * @param schema [in] the table schema to be freed.
 */
void free_table_schema(TableSchema schema);