diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8fe6cc69e0..b78b896908 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -35,7 +35,7 @@ endif(${BUILD_TEST})
add_subdirectory(source)
add_subdirectory(tools)
add_subdirectory(tests)
-add_subdirectory(example)
+add_subdirectory(examples/c)
# docs
add_subdirectory(docs)
diff --git a/cmake/cmake.define b/cmake/cmake.define
index 5637c666b9..8d71870e7d 100644
--- a/cmake/cmake.define
+++ b/cmake/cmake.define
@@ -46,7 +46,7 @@ ENDIF ()
IF (TD_WINDOWS)
MESSAGE("${Yellow} set compiler flag for Windows! ${ColourReset}")
- SET(COMMON_FLAGS "/w /D_WIN32 /Zi")
+ SET(COMMON_FLAGS "/w /D_WIN32 /DWIN32 /Zi")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO")
# IF (MSVC AND (MSVC_VERSION GREATER_EQUAL 1900))
# SET(COMMON_FLAGS "${COMMON_FLAGS} /Wv:18")
diff --git a/docs-cn/12-taos-sql/07-function.md b/docs-cn/12-taos-sql/07-function.md
index d2cd89f152..7674967f09 100644
--- a/docs-cn/12-taos-sql/07-function.md
+++ b/docs-cn/12-taos-sql/07-function.md
@@ -1,6 +1,6 @@
---
-sidebar_label: SQL 函数
-title: SQL 函数
+sidebar_label: 函数
+title: 函数
toc_max_heading_level: 4
---
@@ -20,7 +20,7 @@ toc_max_heading_level: 4
**返回结果类型**:如果输入值为整数,输出值是 UBIGINT 类型。如果输入值是 FLOAT/DOUBLE 数据类型,输出值是 DOUBLE 数据类型。
-**适用数据类型**:不能应用在 timestamp、binary、nchar、bool 类型字段上;在超级表查询中使用时,不能应用在 tag 列
+**适用数据类型**:数值类型。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -38,7 +38,7 @@ toc_max_heading_level: 4
**返回结果类型**:DOUBLE。如果输入值为 NULL,输出值也为 NULL
-**适用数据类型**:不能应用在 timestamp、binary、nchar、bool 类型字段上;在超级表查询中使用时,不能应用在 tag 列
+**适用数据类型**:数值类型。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -56,7 +56,7 @@ toc_max_heading_level: 4
**返回结果类型**:DOUBLE。如果输入值为 NULL,输出值也为 NULL
-**适用数据类型**:不能应用在 timestamp、binary、nchar、bool 类型字段上;在超级表查询中使用时,不能应用在 tag 列
+**适用数据类型**:数值类型。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -75,7 +75,7 @@ toc_max_heading_level: 4
**返回结果类型**:DOUBLE。如果输入值为 NULL,输出值也为 NULL
-**适用数据类型**:不能应用在 timestamp、binary、nchar、bool 类型字段上;在超级表查询中使用时,不能应用在 tag 列
+**适用数据类型**:数值类型。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -94,7 +94,7 @@ SELECT CEIL(field_name) FROM { tb_name | stb_name } [WHERE clause];
**返回结果类型**:与指定列的原始数据类型一致。例如,如果指定列的原始数据类型为 Float,那么返回的数据类型也为 Float;如果指定列的原始数据类型为 Double,那么返回的数据类型也为 Double。
-**适用数据类型**:不能应用在 timestamp、binary、nchar、bool 类型字段上;在超级表查询中使用时,不能应用在 tag 列,无论 tag 列的类型是什么类型。
+**适用数据类型**:数值类型。
**适用于**: 普通表、超级表。
@@ -115,7 +115,7 @@ SELECT CEIL(field_name) FROM { tb_name | stb_name } [WHERE clause];
**返回结果类型**:DOUBLE。如果输入值为 NULL,输出值也为 NULL
-**适用数据类型**:不能应用在 timestamp、binary、nchar、bool 类型字段上;在超级表查询中使用时,不能应用在 tag 列
+**适用数据类型**:数值类型。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -142,7 +142,7 @@ SELECT FLOOR(field_name) FROM { tb_name | stb_name } [WHERE clause];
**返回结果类型**:DOUBLE。如果输入值为 NULL,输出值也为 NULL
-**适用数据类型**:不能应用在 timestamp、binary、nchar、bool 类型字段上;在超级表查询中使用时,不能应用在 tag 列
+**适用数据类型**:数值类型。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -161,7 +161,7 @@ SELECT FLOOR(field_name) FROM { tb_name | stb_name } [WHERE clause];
**返回结果类型**:DOUBLE。如果输入值为 NULL,输出值也为 NULL
-**适用数据类型**:不能应用在 timestamp、binary、nchar、bool 类型字段上;在超级表查询中使用时,不能应用在 tag 列
+**适用数据类型**:数值类型。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -190,7 +190,7 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
**返回结果类型**:DOUBLE。如果输入值为 NULL,输出值也为 NULL
-**适用数据类型**:不能应用在 timestamp、binary、nchar、bool 类型字段上;在超级表查询中使用时,不能应用在 tag 列
+**适用数据类型**:数值类型。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -208,7 +208,7 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
**返回结果类型**:DOUBLE。如果输入值为 NULL,输出值也为 NULL
-**适用数据类型**:不能应用在 timestamp、binary、nchar、bool 类型字段上;在超级表查询中使用时,不能应用在 tag 列
+**适用数据类型**:数值类型。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -226,7 +226,7 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
**返回结果类型**:DOUBLE。如果输入值为 NULL,输出值也为 NULL
-**适用数据类型**:不能应用在 timestamp、binary、nchar、bool 类型字段上;在超级表查询中使用时,不能应用在 tag 列
+**适用数据类型**:数值类型。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -248,7 +248,7 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
**返回结果类型**:INT。如果输入值为NULL,输出值为NULL。
-**适用数据类型**:输入参数是 BINARY 类型或者 NCHAR 类型的字符串或者列。不能应用在 TAG 列。
+**适用数据类型**:VARCHAR, NCHAR
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -262,9 +262,9 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
**功能说明**:字符串连接函数。
-**返回结果类型**:如果所有参数均为BINARY类型,则结果类型为BINARY。如果参数包含NCHAR类型,则结果类型为NCHAR。如果输入值为NULL,输出值为NULL。
+**返回结果类型**:如果所有参数均为 VARCHAR 类型,则结果类型为 VARCHAR。如果参数包含NCHAR类型,则结果类型为NCHAR。如果输入值为NULL,输出值为NULL。
-**适用数据类型**:BINARY, NCHAR。不能应用在 TAG 列。 该函数最小参数个数为2个,最大参数个数为8个。
+**适用数据类型**:VARCHAR, NCHAR。 该函数最小参数个数为2个,最大参数个数为8个。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -279,9 +279,9 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
**功能说明**:带分隔符的字符串连接函数。
-**返回结果类型**:如果所有参数均为BINARY类型,则结果类型为BINARY。如果参数包含NCHAR类型,则结果类型为NCHAR。如果输入值为NULL,输出值为NULL。如果separator值不为NULL,其他输入为NULL,输出为空串。
+**返回结果类型**:如果所有参数均为VARCHAR类型,则结果类型为VARCHAR。如果参数包含NCHAR类型,则结果类型为NCHAR。如果输入值为NULL,输出值为NULL。如果separator值不为NULL,其他输入为NULL,输出为空串。
-**适用数据类型**:BINARY, NCHAR。不能应用在 TAG 列。 该函数最小参数个数为3个,最大参数个数为9个。
+**适用数据类型**:VARCHAR, NCHAR。 该函数最小参数个数为3个,最大参数个数为9个。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -298,7 +298,7 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
**返回结果类型**:INT。
-**适用数据类型**:输入参数是 BINARY 类型或者 NCHAR 类型的字符串或者列。不能应用在 TAG 列。
+**适用数据类型**:输入参数是 VARCHAR 类型或者 NCHAR 类型的字符串或者列。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -315,7 +315,7 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
**返回结果类型**:同输入类型。如果输入值为NULL,输出值为NULL。
-**适用数据类型**:输入参数是 BINARY 类型或者 NCHAR 类型的字符串或者列。不能应用在 TAG 列。
+**适用数据类型**:输入参数是 VARCHAR 类型或者 NCHAR 类型的字符串或者列。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -332,7 +332,7 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
**返回结果类型**:同输入类型。如果输入值为NULL,输出值为NULL。
-**适用数据类型**:输入参数是 BINARY 类型或者 NCHAR 类型的字符串或者列。不能应用在 TAG 列。
+**适用数据类型**:输入参数是 VARCHAR 类型或者 NCHAR 类型的字符串或者列。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -349,7 +349,7 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
**返回结果类型**:同输入类型。如果输入值为NULL,输出值为NULL。
-**适用数据类型**:输入参数是 BINARY 类型或者 NCHAR 类型的字符串或者列。不能应用在 TAG 列。
+**适用数据类型**:输入参数是 VARCHAR 类型或者 NCHAR 类型的字符串或者列。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -366,7 +366,7 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
**返回结果类型**:同输入类型。如果输入值为NULL,输出值为NULL。
-**适用数据类型**:输入参数是 BINARY 类型或者 NCHAR 类型的字符串或者列。不能应用在 TAG 列。输入参数pos可以为正数,也可以为负数。如果pos是正数,表示开始位置从字符串开头正数计算。如果pos为负数,表示开始位置从字符串结尾倒数计算。如果输入参数len被忽略,返回的子串包含从pos开始的整个字串。
+**适用数据类型**:输入参数是 VARCHAR 类型或者 NCHAR 类型的字符串或者列。输入参数pos可以为正数,也可以为负数。如果pos是正数,表示开始位置从字符串开头正数计算。如果pos为负数,表示开始位置从字符串结尾倒数计算。如果输入参数len被忽略,返回的子串包含从pos开始的整个字串。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -383,7 +383,7 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
**返回结果类型**:同输入类型。如果输入值为NULL,输出值为NULL。
-**适用数据类型**:输入参数是 BINARY 类型或者 NCHAR 类型的字符串或者列。不能应用在 TAG 列。
+**适用数据类型**:输入参数是 VARCHAR 类型或者 NCHAR 类型的字符串或者列。
**嵌套子查询支持**:适用于内层查询和外层查询。
@@ -400,7 +400,7 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
SELECT CAST(expression AS type_name) FROM { tb_name | stb_name } [WHERE clause]
```
-**功能说明**:数据类型转换函数,输入参数 expression 支持普通列、常量、标量函数及它们之间的四则运算,不支持 tag 列,只适用于 select 子句中。
+**功能说明**:数据类型转换函数,输入参数 expression 支持普通列、常量、标量函数及它们之间的四则运算,只适用于 select 子句中。
**返回结果类型**:CAST 中指定的类型(type_name),可以是 BIGINT、BIGINT UNSIGNED、BINARY、VARCHAR、NCHAR和TIMESTAMP。
@@ -423,7 +423,7 @@ SELECT TO_ISO8601(ts_val | ts_col) FROM { tb_name | stb_name } [WHERE clause];
**功能说明**:将 UNIX 时间戳转换成为 ISO8601 标准的日期时间格式,并附加客户端时区信息。
-**返回结果数据类型**:BINARY 类型。
+**返回结果数据类型**:VARCHAR 类型。
**适用数据类型**:UNIX 时间戳常量或是 TIMESTAMP 类型的列
@@ -462,7 +462,7 @@ SELECT TO_UNIXTIMESTAMP(datetime_string | ts_col) FROM { tb_name | stb_name } [W
**返回结果数据类型**:长整型 INT64。
-**应用字段**:字符串常量或是 BINARY/NCHAR 类型的列。
+**应用字段**:字符串常量或是 VARCHAR/NCHAR 类型的列。
**适用于**:表、超级表。
@@ -549,7 +549,7 @@ SELECT TIMEZONE() FROM { tb_name | stb_name } [WHERE clause];
**功能说明**:返回客户端当前时区信息。
-**返回结果数据类型**:BINARY 类型。
+**返回结果数据类型**:VARCHAR 类型。
**应用字段**:无
@@ -668,7 +668,7 @@ SELECT LEASTSQUARES(field_name, start_val, step_val) FROM tb_name [WHERE clause]
SELECT MODE(field_name) FROM tb_name [WHERE clause];
```
-**功能说明**:返回出现频率最高的值,若存在多个频率相同的最高值,输出空。不能匹配标签、时间戳输出。
+**功能说明**:返回出现频率最高的值,若存在多个频率相同的最高值,输出空。
**返回数据类型**:同应用的字段。
@@ -808,6 +808,25 @@ SELECT BOTTOM(field_name, K) FROM { tb_name | stb_name } [WHERE clause];
- 系统同时返回该记录关联的时间戳列;
- 限制:BOTTOM 函数不支持 FILL 子句。
+### FIRST
+
+```
+SELECT FIRST(field_name) FROM { tb_name | stb_name } [WHERE clause];
+```
+
+**功能说明**:统计表/超级表中某列的值最先写入的非 NULL 值。
+
+**返回数据类型**:同应用的字段。
+
+**适用数据类型**:所有字段。
+
+**适用于**:表和超级表。
+
+**使用说明**:
+
+- 如果要返回各个列的首个(时间戳最小)非 NULL 值,可以使用 FIRST(\*);
+- 如果结果集中的某列全部为 NULL 值,则该列的返回结果也是 NULL;
+- 如果结果集中所有列全部为 NULL 值,则不返回结果。
### INTERP
@@ -919,25 +938,6 @@ SELECT PERCENTILE(field_name, P) FROM { tb_name } [WHERE clause];
**使用说明**:*P*值取值范围 0≤*P*≤100,为 0 的时候等同于 MIN,为 100 的时候等同于 MAX。
-### FIRST
-
-```
-SELECT FIRST(field_name) FROM { tb_name | stb_name } [WHERE clause];
-```
-
-**功能说明**:统计表/超级表中某列的值最先写入的非 NULL 值。
-
-**返回数据类型**:同应用的字段。
-
-**适用数据类型**:所有字段。
-
-**适用于**:表和超级表。
-
-**使用说明**:
-
-- 如果要返回各个列的首个(时间戳最小)非 NULL 值,可以使用 FIRST(\*);
-- 如果结果集中的某列全部为 NULL 值,则该列的返回结果也是 NULL;
-- 如果结果集中所有列全部为 NULL 值,则不返回结果。
### TAIL
@@ -1005,7 +1005,7 @@ SELECT UNIQUE(field_name) FROM {tb_name | stb_name} [WHERE clause];
**返回结果类型**: 输入列如果是整数类型返回值为长整型 (int64_t),浮点数返回值为双精度浮点数(Double)。无符号整数类型返回值为无符号长整型(uint64_t)。 返回结果中同时带有每行记录对应的时间戳。
-**适用数据类型**:不能应用在 timestamp、binary、nchar、bool 类型字段上;在超级表查询中使用时,不能应用在标签之上。
+**适用数据类型**:数值类型。
**嵌套子查询支持**: 适用于内层查询和外层查询。
@@ -1076,7 +1076,7 @@ SELECT IRATE(field_name) FROM tb_name WHERE clause;
**返回结果类型**: 返回双精度浮点数类型。
- **适用数据类型**: 不能应用在 timestamp、binary、nchar、bool 类型上;在超级表查询中使用时,不能应用在标签之上。
+ **适用数据类型**: 数值类型。
**嵌套子查询支持**: 适用于内层查询和外层查询。
@@ -1124,7 +1124,7 @@ SELECT STATECOUNT(field_name, oper, val) FROM { tb_name | stb_name } [WHERE clau
**返回结果类型**:整形。
-**适用数据类型**:不能应用在 timestamp、binary、nchar、bool 类型字段上。
+**适用数据类型**:数值类型。
**嵌套子查询支持**:不支持应用在子查询上。
@@ -1152,7 +1152,7 @@ SELECT stateDuration(field_name, oper, val, unit) FROM { tb_name | stb_name } [W
**返回结果类型**:整形。
-**适用数据类型**:不能应用在 timestamp、binary、nchar、bool 类型字段上。
+**适用数据类型**:数值类型。
**嵌套子查询支持**:不支持应用在子查询上。
diff --git a/docs-cn/12-taos-sql/13-operators.md b/docs-cn/12-taos-sql/13-operators.md
index 1ffc823044..22b78455fb 100644
--- a/docs-cn/12-taos-sql/13-operators.md
+++ b/docs-cn/12-taos-sql/13-operators.md
@@ -35,8 +35,8 @@ TDengine 支持 `UNION ALL` 和 `UNION` 操作符。UNION ALL 将查询返回的
| --- | :---------------: | -------------------------------------------------------------------- | -------------------- |
| 1 | = | 除 BLOB、MEDIUMBLOB 和 JSON 外的所有类型 | 相等 |
| 2 | <\>, != | 除 BLOB、MEDIUMBLOB 和 JSON 外的所有类型,且不可以为表的时间戳主键列 | 不相等 |
-| 3 | \>, \< | 除 BLOB、MEDIUMBLOB 和 JSON 外的所有类型 | 大于,小于 |
-| 4 | \>=, \<= | 除 BLOB、MEDIUMBLOB 和 JSON 外的所有类型 | 大于等于,小于等于 |
+| 3 | \>, < | 除 BLOB、MEDIUMBLOB 和 JSON 外的所有类型 | 大于,小于 |
+| 4 | \>=, <= | 除 BLOB、MEDIUMBLOB 和 JSON 外的所有类型 | 大于等于,小于等于 |
| 5 | IS [NOT] NULL | 所有类型 | 是否为空值 |
| 6 | [NOT] BETWEEN AND | 除 BOOL、BLOB、MEDIUMBLOB 和 JSON 外的所有类型 | 闭区间比较 |
| 7 | IN | 除 BLOB、MEDIUMBLOB 和 JSON 外的所有类型,且不可以为表的时间戳主键列 | 与列表内的任意值相等 |
diff --git a/docs-cn/14-reference/03-connector/cpp.mdx b/docs-cn/14-reference/03-connector/cpp.mdx
index aba1d6c717..aecf9fde12 100644
--- a/docs-cn/14-reference/03-connector/cpp.mdx
+++ b/docs-cn/14-reference/03-connector/cpp.mdx
@@ -114,7 +114,6 @@ TDengine 客户端驱动的安装请参考 [安装指南](/reference/connector#
订阅和消费
```c
-{{#include examples/c/subscribe.c}}
```
diff --git a/docs-cn/20-third-party/01-grafana.mdx b/docs-cn/20-third-party/01-grafana.mdx
index 328bd6bb45..40b5c0ff4f 100644
--- a/docs-cn/20-third-party/01-grafana.mdx
+++ b/docs-cn/20-third-party/01-grafana.mdx
@@ -18,21 +18,22 @@ TDengine 能够与开源数据可视化系统 [Grafana](https://www.grafana.com/
## 配置 Grafana
-TDengine 的 Grafana 插件托管在 GitHub,可从 下载,当前最新版本为 3.1.4。
-
-推荐使用 [`grafana-cli` 命令行工具](https://grafana.com/docs/grafana/latest/administration/cli/) 进行插件安装。
+使用 [`grafana-cli` 命令行工具](https://grafana.com/docs/grafana/latest/administration/cli/) 进行插件[安装](https://grafana.com/grafana/plugins/tdengine-datasource/?tab=installation)。
```bash
-sudo -u grafana grafana-cli \
- --pluginUrl https://github.com/taosdata/grafanaplugin/releases/download/v3.1.7/tdengine-datasource-3.1.7.zip \
- plugins install tdengine-datasource
+grafana-cli plugins install tdengine-datasource
+# with sudo
+sudo -u grafana grafana-cli plugins install tdengine-datasource
```
-或者下载到本地并解压到 Grafana 插件目录。
+或者从 [GitHub](https://github.com/taosdata/grafanaplugin/releases/tag/latest) 或 [Grafana](https://grafana.com/grafana/plugins/tdengine-datasource/?tab=installation) 下载 .zip 文件到本地并解压到 Grafana 插件目录。命令行下载示例如下:
```bash
-GF_VERSION=3.1.7
+GF_VERSION=3.2.2
+# from GitHub
wget https://github.com/taosdata/grafanaplugin/releases/download/v$GF_VERSION/tdengine-datasource-$GF_VERSION.zip
+# from Grafana
+wget -O tdengine-datasource-$GF_VERSION.zip https://grafana.com/api/plugins/tdengine-datasource/versions/$GF_VERSION/download
```
以 CentOS 7.2 操作系统为例,将插件包解压到 /var/lib/grafana/plugins 目录下,重新启动 grafana 即可。
@@ -41,28 +42,17 @@ wget https://github.com/taosdata/grafanaplugin/releases/download/v$GF_VERSION/td
sudo unzip tdengine-datasource-$GF_VERSION.zip -d /var/lib/grafana/plugins/
```
-:::note
-3.1.6 和更早版本未签名,会在 Grafana 7.3+ / 8.x 版本签名检查时失败导致无法加载插件,需要在 grafana.ini 文件中修改配置如下:
-
-```ini
-[plugins]
-allow_loading_unsigned_plugins = tdengine-datasource
-```
-
-:::
-
-在 Docker 环境下,可以使用如下的环境变量设置自动安装并设置 TDengine 插件:
+如果 Grafana 在 Docker 环境下运行,可以使用如下的环境变量设置自动安装 TDengine 数据源插件:
```bash
-GF_INSTALL_PLUGINS=https://github.com/taosdata/grafanaplugin/releases/download/v3.1.4/tdengine-datasource-3.1.4.zip;tdengine-datasource
-GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=tdengine-datasource
+GF_INSTALL_PLUGINS=tdengine-datasource
```
## 使用 Grafana
### 配置数据源
-用户可以直接通过 http://localhost:3000 的网址,登录 Grafana 服务器(用户名/密码:admin/admin),通过左侧 `Configuration -> Data Sources` 可以添加数据源,如下图所示:
+用户可以直接通过 的网址,登录 Grafana 服务器(用户名/密码:admin/admin),通过左侧 `Configuration -> Data Sources` 可以添加数据源,如下图所示:

@@ -74,7 +64,7 @@ GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=tdengine-datasource

-- Host: TDengine 集群中提供 REST 服务 (在 2.4 之前由 taosd 提供, 从 2.4 开始由 taosAdapter 提供)的组件所在服务器的 IP 地址与 TDengine REST 服务的端口号(6041),默认 http://localhost:6041。
+- Host: TDengine 集群中提供 REST 服务 (在 2.4 之前由 taosd 提供, 从 2.4 开始由 taosAdapter 提供)的组件所在服务器的 IP 地址与 TDengine REST 服务的端口号(6041),默认 。
- User:TDengine 用户名。
- Password:TDengine 用户密码。
diff --git a/docs-en/12-taos-sql/07-function.md b/docs-en/12-taos-sql/07-function.md
index 1a0dc28fa0..129b7eb0c3 100644
--- a/docs-en/12-taos-sql/07-function.md
+++ b/docs-en/12-taos-sql/07-function.md
@@ -1,10 +1,635 @@
---
title: Functions
+toc_max_heading_level: 4
---
+## Single-Row Functions
+
+Single-Row functions return a result row for each row in the query result.
+
+### Numeric Functions
+
+#### ABS
+
+```sql
+SELECT ABS(field_name) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: The absolute of a specific column.
+
+**Return value type**: UBIGINT if the input value is integer; DOUBLE if the input value is FLOAT/DOUBLE.
+
+**Applicable data types**: Numeric types.
+
+**Applicable table types**: table, STable.
+
+**Applicable nested query**: Inner query and Outer query.
+
+**More explanations**:
+- Can't be used with aggregate functions.
+
+#### ACOS
+
+```sql
+SELECT ACOS(field_name) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: The anti-cosine of a specific column
+
+**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
+
+**Applicable data types**: Numeric types.
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**:
+- Can't be used with aggregate functions
+
+#### ASIN
+
+```sql
+SELECT ASIN(field_name) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: The anti-sine of a specific column
+
+**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
+
+**Applicable data types**: Numeric types.
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**:
+- Can't be used with aggregate functions
+
+#### ATAN
+
+```sql
+SELECT ATAN(field_name) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: anti-tangent of a specific column
+
+**Description**: The anti-cosine of a specific column
+
+**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
+
+**Applicable data types**: Numeric types.
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**:
+- Can't be used with aggregate functions
+
+#### CEIL
+
+```
+SELECT CEIL(field_name) FROM { tb_name | stb_name } [WHERE clause];
+```
+
+**Description**: The rounded up value of a specific column
+
+**Return value type**: Same as the column being used
+
+**Applicable data types**: Numeric types.
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and outer query
+
+**More explanations**:
+- Arithmetic operation can be performed on the result of `ceil` function
+- Can't be used with aggregate functions
+
+#### COS
+
+```sql
+SELECT COS(field_name) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: The cosine of a specific column
+
+**Description**: The anti-cosine of a specific column
+
+**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
+
+**Applicable data types**: Numeric types.
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**:
+- Can't be used with aggregate functions
+
+#### FLOOR
+
+```
+SELECT FLOOR(field_name) FROM { tb_name | stb_name } [WHERE clause];
+```
+
+**Description**: The rounded down value of a specific column
+
+**More explanations**: The restrictions are same as those of the `CEIL` function.
+
+#### LOG
+
+```sql
+SELECT LOG(field_name, base) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: The log of a specific with `base` as the radix
+
+**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
+
+**Applicable data types**: Numeric types.
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**:
+- Can't be used with aggregate functions
+
+#### POW
+
+```sql
+SELECT POW(field_name, power) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: The power of a specific column with `power` as the index
+
+**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
+
+**Applicable data types**: Numeric types.
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**:
+- Can't be used with aggregate functions
+
+#### ROUND
+
+```
+SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
+```
+
+**Description**: The rounded value of a specific column.
+
+**More explanations**: The restrictions are same as `CEIL` function.
+
+#### SIN
+
+```sql
+SELECT SIN(field_name) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: The sine of a specific column
+
+**Description**: The anti-cosine of a specific column
+
+**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
+
+**Applicable data types**: Numeric types.
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**:
+- Can't be used with aggregate functions
+
+#### SQRT
+
+```sql
+SELECT SQRT(field_name) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: The square root of a specific column
+
+**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
+
+**Applicable data types**: Numeric types.
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**:
+- Can't be used with aggregate functions
+
+#### TAN
+
+```sql
+SELECT TAN(field_name) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: The tangent of a specific column
+
+**Description**: The anti-cosine of a specific column
+
+**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
+
+**Applicable data types**: Numeric types.
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**:
+- Can't be used with aggregate functions
+
+### String Functions
+
+String functiosn take strings as input and output numbers or strings.
+
+#### CHAR_LENGTH
+
+```
+SELECT CHAR_LENGTH(str|column) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: The length in number of characters of a string
+
+**Return value type**: Integer
+
+**Applicable data types**: VARCHAR or NCHAR
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**
+
+- If the input value is NULL, the output is NULL too
+
+#### CONCAT
+
+```sql
+SELECT CONCAT(str1|column1, str2|column2, ...) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: The concatenation result of two or more strings, the number of strings to be concatenated is at least 2 and at most 8
+
+**Return value type**: If all input strings are VARCHAR type, the result is VARCHAR type too. If any one of input strings is NCHAR type, then the result is NCHAR.
+
+**Applicable data types**: VARCHAR, NCHAR. At least 2 input strings are requird, and at most 8 input strings are allowed.
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+#### CONCAT_WS
+
+```
+SELECT CONCAT_WS(separator, str1|column1, str2|column2, ...) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: The concatenation result of two or more strings with separator, the number of strings to be concatenated is at least 3 and at most 9
+
+**Return value type**: If all input strings are VARCHAR type, the result is VARCHAR type too. If any one of input strings is NCHAR type, then the result is NCHAR.
+
+**Applicable data types**: VARCHAR, NCHAR. At least 3 input strings are requird, and at most 9 input strings are allowed.
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**:
+
+- If the value of `separator` is NULL, the output is NULL. If the value of `separator` is not NULL but other input are all NULL, the output is empty string.
+
+#### LENGTH
+
+```
+SELECT LENGTH(str|column) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: The length in bytes of a string
+
+**Return value type**: Integer
+
+**Applicable data types**: VARCHAR or NCHAR
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**
+
+- If the input value is NULL, the output is NULL too
+
+#### LOWER
+
+```
+SELECT LOWER(str|column) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: Convert the input string to lower case
+
+**Return value type**: Same as input
+
+**Applicable data types**: VARCHAR or NCHAR
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**
+
+- If the input value is NULL, the output is NULL too
+
+#### LTRIM
+
+```
+SELECT LTRIM(str|column) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: Remove the left leading blanks of a string
+
+**Return value type**: Same as input
+
+**Applicable data types**: VARCHAR or NCHAR
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**
+
+- If the input value is NULL, the output is NULL too
+
+#### RTRIM
+
+```
+SELECT RTRIM(str|column) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: Remove the right tailing blanks of a string
+
+**Return value type**: Same as input
+
+**Applicable data types**: VARCHAR or NCHAR
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**
+
+- If the input value is NULL, the output is NULL too
+
+#### SUBSTR
+
+```
+SELECT SUBSTR(str,pos[,len]) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: The sub-string starting from `pos` with length of `len` from the original string `str`
+
+**Return value type**: Same as input
+
+**Applicable data types**: VARCHAR or NCHAR
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**:
+
+- If the input is NULL, the output is NULL
+- Parameter `pos` can be an positive or negative integer; If it's positive, the starting position will be counted from the beginning of the string; if it's negative, the starting position will be counted from the end of the string.
+- If `len` is not specified, it means from `pos` to the end.
+
+#### UPPER
+
+```
+SELECT UPPER(str|column) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: Convert the input string to upper case
+
+**Return value type**: Same as input
+
+**Applicable data types**: VARCHAR or NCHAR
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query
+
+**More explanations**
+
+- If the input value is NULL, the output is NULL too
+
+### Conversion Functions
+
+This kind of functions convert from one data type to another one.
+
+#### CAST
+
+```sql
+SELECT CAST(expression AS type_name) FROM { tb_name | stb_name } [WHERE clause]
+```
+
+**Description**: It's used for type casting. The input parameter `expression` can be data columns, constants, scalar functions or arithmetic between them.
+
+**Return value type**: The type specified by parameter `type_name`
+
+**Applicable data types**:
+
+- Parameter `expression` can be any data type except for JSON
+- The output data type specified by `type_name` can only be one of BIGINT/VARCHAR(N)/TIMESTAMP/NCHAR(N)/BIGINT UNSIGNED
+
+**More explanations**:
+
+- Error will be reported for unsupported type casting
+- NULL will be returned if the input value is NULL
+- Some values of some supported data types may not be casted, below are known issues:
+ 1)When casting VARCHAR/NCHAR to BIGINT/BIGINT UNSIGNED, some characters may be treated as illegal, for example "a" may be converted to 0.
+ 2)There may be overflow when casting singed integer or TIMESTAMP to unsigned BIGINT
+ 3)There may be overflow when casting unsigned BIGINT to BIGINT
+ 4)There may be overflow when casting FLOAT/DOUBLE to BIGINT or UNSIGNED BIGINT
+
+#### TO_ISO8601
+
+```sql
+SELECT TO_ISO8601(ts_val | ts_col) FROM { tb_name | stb_name } [WHERE clause];
+```
+
+**Description**: The ISO8601 date/time format converted from a UNIX timestamp, plus the timezone of the client side system
+
+**Return value type**: VARCHAR
+
+**Applicable column types**: TIMESTAMP, constant or a column
+
+**Applicable table types**: table, STable
+
+**More explanations**:
+
+- If the input is UNIX timestamp constant, the precision of the returned value is determined by the digits of the input timestamp
+- If the input is a column of TIMESTAMP type, The precision of the returned value is same as the precision set for the current data base in use
+
+#### TO_JSON
+
+```sql
+SELECT TO_JSON(str_literal) FROM { tb_name | stb_name } [WHERE clause];
+```
+
+**Description**: Convert a JSON string to a JSON body。
+
+**Return value type**: JSON
+
+**Applicable column types**: JSON string, in the format like '{ "literal" : literal }'. '{}' is NULL value. keys in the string must be string constants, values can be constants of numeric types, bool, string or NULL. Escaping characters are not allowed in the JSON string.
+
+**Applicable table types**: table, STable
+
+**Applicable nested query**: Inner query and Outer query.
+
+#### TO_UNIXTIMESTAMP
+
+```sql
+SELECT TO_UNIXTIMESTAMP(datetime_string | ts_col) FROM { tb_name | stb_name } [WHERE clause];
+```
+
+**Description**: UNIX timestamp converted from a string of date/time format
+
+**Return value type**: Long integer
+
+**Applicable column types**: Constant or column of VARCHAR/NCHAR
+
+**Applicable table types**: table, STable
+
+**More explanations**:
+
+- The input string must be compatible with ISO8601/RFC3339 standard, 0 will be returned if the string can't be converted
+- The precision of the returned timestamp is same as the precision set for the current data base in use
+
+### DateTime Functions
+
+This kind of functiosn oeprate on timestamp data. NOW(), TODAY() and TIMEZONE() are executed only once even though they may occurr multiple times in a single SQL statement.
+
+#### NOW
+
+```sql
+SELECT NOW() FROM { tb_name | stb_name } [WHERE clause];
+SELECT select_expr FROM { tb_name | stb_name } WHERE ts_col cond_operatior NOW();
+INSERT INTO tb_name VALUES (NOW(), ...);
+```
+
+**Description**: The current time of the client side system
+
+**Return value type**: TIMESTAMP
+
+**Applicable column types**: TIMESTAMP only
+
+**Applicable table types**: table, STable
+
+**More explanations**:
+
+- Add and Subtract operation can be performed, for example NOW() + 1s, the time unit can be:
+ b(nanosecond), u(microsecond), a(millisecond)), s(second), m(minute), h(hour), d(day), w(week)
+- The precision of the returned timestamp is same as the precision set for the current data base in use
+
+#### TIMEDIFF
+
+```sql
+SELECT TIMEDIFF(ts_val1 | datetime_string1 | ts_col1, ts_val2 | datetime_string2 | ts_col2 [, time_unit]) FROM { tb_name | stb_name } [WHERE clause];
+```
+
+**Description**: The difference between two timestamps, and rounded to the time unit specified by `time_unit`
+
+**Return value type**: Long Integer
+
+**Applicable column types**: UNIX timestamp constant, string constant of date/time format, or a column of TIMESTAMP type
+
+**Applicable table types**: table, STable
+
+**More explanations**:
+
+- Time unit specified by `time_unit` can be:
+ 1u(microsecond),1a(millisecond),1s(second),1m(minute),1h(hour),1d(day).
+- The precision of the returned timestamp is same as the precision set for the current data base in use
+
+#### TIMETRUNCATE
+
+```sql
+SELECT TIMETRUNCATE(ts_val | datetime_string | ts_col, time_unit) FROM { tb_name | stb_name } [WHERE clause];
+```
+
+**Description**: Truncate the input timestamp with unit specified by `time_unit`
+
+**Return value type**: TIMESTAMP
+
+**Applicable column types**: UNIX timestamp constant, string constant of date/time format, or a column of timestamp
+
+**Applicable table types**: table, STable
+
+**More explanations**:
+
+- Time unit specified by `time_unit` can be:
+ 1u(microsecond),1a(millisecond),1s(second),1m(minute),1h(hour),1d(day).
+- The precision of the returned timestamp is same as the precision set for the current data base in use
+
+#### TIMEZONE
+
+```sql
+SELECT TIMEZONE() FROM { tb_name | stb_name } [WHERE clause];
+```
+
+**Description**: The timezone of the client side system
+
+**Return value type**: VARCHAR
+
+**Applicable column types**: None
+
+**Applicable table types**: table, STable
+
+#### TODAY
+
+```sql
+SELECT TODAY() FROM { tb_name | stb_name } [WHERE clause];
+SELECT select_expr FROM { tb_name | stb_name } WHERE ts_col cond_operatior TODAY()];
+INSERT INTO tb_name VALUES (TODAY(), ...);
+```
+
+**Description**: The timestamp of 00:00:00 of the client side system
+
+**Return value type**: TIMESTAMP
+
+**Applicable column types**: TIMESTAMP only
+
+**Applicable table types**: table, STable
+
+**More explanations**:
+
+- Add and Subtract operation can be performed, for example NOW() + 1s, the time unit can be:
+ b(nanosecond), u(microsecond), a(millisecond)), s(second), m(minute), h(hour), d(day), w(week)
+- The precision of the returned timestamp is same as the precision set for the current data base in use
+
## Aggregate Functions
-Aggregate queries are supported in TDengine by the following aggregate functions and selection functions.
+Aggregate functions return single result row for each group in the query result set. Groups are determined by `GROUP BY` clause or time window clause if they are used; or the whole result is considered a group if neither of them is used.
+
+### AVG
+
+```
+SELECT AVG(field_name) FROM tb_name [WHERE clause];
+```
+
+**Description**: Get the average value of a column in a table or STable
+
+**Return value type**: Double precision floating number
+
+**Applicable column types**: Numeric type
+
+**Applicable table types**: table, STable
### COUNT
@@ -25,141 +650,30 @@ SELECT COUNT([*|field_name]) FROM tb_name [WHERE clause];
- Wildcard (\*) is used to represent all columns. The `COUNT` function is used to get the total number of all rows.
- The number of non-NULL values will be returned if this function is used on a specific column.
-**Examples**:
+### ELAPSED
-```
-taos> SELECT COUNT(*), COUNT(voltage) FROM meters;
- count(*) | count(voltage) |
-================================================
- 9 | 9 |
-Query OK, 1 row(s) in set (0.004475s)
-
-taos> SELECT COUNT(*), COUNT(voltage) FROM d1001;
- count(*) | count(voltage) |
-================================================
- 3 | 3 |
-Query OK, 1 row(s) in set (0.001075s)
+```mysql
+SELECT ELAPSED(field_name[, time_unit]) FROM { tb_name | stb_name } [WHERE clause] [INTERVAL(interval [, offset]) [SLIDING sliding]];
```
-### AVG
+**Description**:`elapsed` function can be used to calculate the continuous time length in which there is valid data. If it's used with `INTERVAL` clause, the returned result is the calcualted time length within each time window. If it's used without `INTERVAL` caluse, the returned result is the calculated time length within the specified time range. Please be noted that the return value of `elapsed` is the number of `time_unit` in the calculated time length.
-```
-SELECT AVG(field_name) FROM tb_name [WHERE clause];
-```
+**Return value type**:Double
-**Description**: Get the average value of a column in a table or STable
+**Applicable Column type**:Timestamp
-**Return value type**: Double precision floating number
+**Applicable tables**: table, STable, outter in nested query
-**Applicable column types**: Data types except for timestamp, binary, nchar and bool
+**Explanations**:
-**Applicable table types**: table, STable
-
-**Examples**:
-
-```
-taos> SELECT AVG(current), AVG(voltage), AVG(phase) FROM meters;
- avg(current) | avg(voltage) | avg(phase) |
-====================================================================================
- 11.466666751 | 220.444444444 | 0.293333333 |
-Query OK, 1 row(s) in set (0.004135s)
-
-taos> SELECT AVG(current), AVG(voltage), AVG(phase) FROM d1001;
- avg(current) | avg(voltage) | avg(phase) |
-====================================================================================
- 11.733333588 | 219.333333333 | 0.316666673 |
-Query OK, 1 row(s) in set (0.000943s)
-```
-
-### TWA
-
-```
-SELECT TWA(field_name) FROM tb_name WHERE clause;
-```
-
-**Description**: Time weighted average on a specific column within a time range
-
-**Return value type**: Double precision floating number
-
-**Applicable column types**: Data types except for timestamp, binary, nchar and bool
-
-**Applicable table types**: table, STable
-
-**More explanations**:
-
-- Since version 2.1.3.0, function TWA can be used on stable with `GROUP BY`, i.e. timelines generated by `GROUP BY tbname` on a STable.
-
-### IRATE
-
-```
-SELECT IRATE(field_name) FROM tb_name WHERE clause;
-```
-
-**Description**: instantaneous rate on a specific column. The last two samples in the specified time range are used to calculate instantaneous rate. If the last sample value is smaller, then only the last sample value is used instead of the difference between the last two sample values.
-
-**Return value type**: Double precision floating number
-
-**Applicable column types**: Data types except for timestamp, binary, nchar and bool
-
-**Applicable table types**: table, STable
-
-**More explanations**:
-
-- Since version 2.1.3.0, function IRATE can be used on stble with `GROUP BY`, i.e. timelines generated by `GROUP BY tbname` on a STable.
-
-### SUM
-
-```
-SELECT SUM(field_name) FROM tb_name [WHERE clause];
-```
-
-**Description**: The sum of a specific column in a table or STable
-
-**Return value type**: Double precision floating number or long integer
-
-**Applicable column types**: Data types except for timestamp, binary, nchar and bool
-
-**Applicable table types**: table, STable
-
-**Examples**:
-
-```
-taos> SELECT SUM(current), SUM(voltage), SUM(phase) FROM meters;
- sum(current) | sum(voltage) | sum(phase) |
-================================================================================
- 103.200000763 | 1984 | 2.640000001 |
-Query OK, 1 row(s) in set (0.001702s)
-
-taos> SELECT SUM(current), SUM(voltage), SUM(phase) FROM d1001;
- sum(current) | sum(voltage) | sum(phase) |
-================================================================================
- 35.200000763 | 658 | 0.950000018 |
-Query OK, 1 row(s) in set (0.000980s)
-```
-
-### STDDEV
-
-```
-SELECT STDDEV(field_name) FROM tb_name [WHERE clause];
-```
-
-**Description**: Standard deviation of a specific column in a table or STable
-
-**Return value type**: Double precision floating number
-
-**Applicable column types**: Data types except for timestamp, binary, nchar and bool
-
-**Applicable table types**: table, STable (since version 2.0.15.1)
-
-**Examples**:
-
-```
-taos> SELECT STDDEV(current) FROM d1001;
- stddev(current) |
-============================
- 1.020892909 |
-Query OK, 1 row(s) in set (0.000915s)
-```
+- `field_name` parameter can only be the first column of a table, i.e. timestamp primary key.
+- The minimum value of `time_unit` is the time precision of the database. If `time_unit` is not specified, the time precision of the database is used as the default ime unit.
+- It can be used with `INTERVAL` to get the time valid time length of each time window. Please be noted that the return value is same as the time window for all time windows except for the first and the last time window.
+- `order by asc/desc` has no effect on the result.
+- `group by tbname` must be used together when `elapsed` is used against a STable.
+- `group by` must NOT be used together when `elapsed` is used against a table or sub table.
+- When used in nested query, it's only applicable when the inner query outputs an implicit timestamp column as the primary key. For example, `select elapsed(ts) from (select diff(value) from sub1)` is legal usage while `select elapsed(ts) from (select * from sub1)` is not.
+- It can't be used with `leastsquares`, `diff`, `derivative`, `top`, `bottom`, `last_row`, `interp`.
### LEASTSQUARES
@@ -171,27 +685,17 @@ SELECT LEASTSQUARES(field_name, start_val, step_val) FROM tb_name [WHERE clause]
**Return value type**: A string in the format of "(slope, intercept)"
-**Applicable column types**: Data types except for timestamp, binary, nchar and bool
+**Applicable column types**: Numeric types
**Applicable table types**: table only
-**Examples**:
-
-```
-taos> SELECT LEASTSQUARES(current, 1, 1) FROM d1001;
- leastsquares(current, 1, 1) |
-=====================================================
-{slop:1.000000, intercept:9.733334} |
-Query OK, 1 row(s) in set (0.000921s)
-```
-
### MODE
```
SELECT MODE(field_name) FROM tb_name [WHERE clause];
```
-**Description**:The value which has the highest frequency of occurrence. NULL is returned if there are multiple values which have highest frequency of occurrence. It can't be used on timestamp column or tags.
+**Description**:The value which has the highest frequency of occurrence. NULL is returned if there are multiple values which have highest frequency of occurrence. It can't be used on timestamp column.
**Return value type**:Same as the data type of the column being operated upon
@@ -199,27 +703,50 @@ SELECT MODE(field_name) FROM tb_name [WHERE clause];
**More explanations**:Considering the number of returned result set is unpredictable, it's suggested to limit the number of unique values to 100,000, otherwise error will be returned.
-**Applicable version**:Since version 2.6.0.0
-
-**Examples**:
+### SPREAD
```
-taos> select voltage from d002;
- voltage |
-========================
- 1 |
- 1 |
- 2 |
- 19 |
-Query OK, 4 row(s) in set (0.003545s)
-
-taos> select mode(voltage) from d002;
- mode(voltage) |
-========================
- 1 |
-Query OK, 1 row(s) in set (0.019393s)
+SELECT SPREAD(field_name) FROM { tb_name | stb_name } [WHERE clause];
```
+**Description**: The difference between the max and the min of a specific column
+
+**Return value type**: Double precision floating point
+
+**Applicable column types**: Numeric types
+
+**Applicable table types**: table, STable
+
+**More explanations**: Can be used on a column of TIMESTAMP type, the result is the time range size.
+
+### STDDEV
+
+```
+SELECT STDDEV(field_name) FROM tb_name [WHERE clause];
+```
+
+**Description**: Standard deviation of a specific column in a table or STable
+
+**Return value type**: Double precision floating number
+
+**Applicable column types**: Numeric types
+
+**Applicable table types**: table, STable
+
+### SUM
+
+```
+SELECT SUM(field_name) FROM tb_name [WHERE clause];
+```
+
+**Description**: The sum of a specific column in a table or STable
+
+**Return value type**: Double precision floating number or long integer
+
+**Applicable column types**: Numeric types
+
+**Applicable table types**: table, STable
+
### HYPERLOGLOG
```
@@ -234,31 +761,6 @@ SELECT HYPERLOGLOG(field_name) FROM { tb_name | stb_name } [WHERE clause];
**More explanations**: The benefit of using hyperloglog algorithm is that the memory usage is under control when the data volume is huge. However, when the data volume is very small, the result may be not accurate, it's recommented to use `select count(data) from (select unique(col) as data from table)` in this case.
-**Applicable versions**:Since version 2.6.0.0
-
-**Examples**:
-
-```
-taos> select dbig from shll;
- dbig |
-========================
- 1 |
- 1 |
- 1 |
- NULL |
- 2 |
- 19 |
- NULL |
- 9 |
-Query OK, 8 row(s) in set (0.003755s)
-
-taos> select hyperloglog(dbig) from shll;
- hyperloglog(dbig)|
-========================
- 4 |
-Query OK, 1 row(s) in set (0.008388s)
-```
-
### HISTOGRAM
```
@@ -271,151 +773,77 @@ SELECT HISTOGRAM(field_name,bin_type, bin_description, normalized) FROM tb_nam
**Applicable column type**:Numerical types.
-**Applicable versions**:Since version 2.6.0.0.
-
**Applicable table types**: table, STable
**Explanations**:
1. bin_type: parameter to indicate the bucket type, valid inputs are: "user_input", "linear_bin", "log_bin"。
-2. bin_description: parameter to describe how to generate buckets,can be in the following JSON formats for each bin_type respectively:
+2. bin_description: parameter to describe how to generate buckets,can be in the following JSON formats for each bin_type respectively:
- - "user_input": "[1, 3, 5, 7]": User specified bin values.
+ - "user_input": "[1, 3, 5, 7]": User specified bin values.
- - "linear_bin": "{"start": 0.0, "width": 5.0, "count": 5, "infinity": true}"
- "start" - bin starting point.
- "width" - bin offset.
- "count" - number of bins generated.
- "infinity" - whether to add(-inf, inf)as start/end point in generated set of bins.
- The above "linear_bin" descriptor generates a set of bins: [-inf, 0.0, 5.0, 10.0, 15.0, 20.0, +inf].
+ - "linear_bin": "{"start": 0.0, "width": 5.0, "count": 5, "infinity": true}"
+ "start" - bin starting point.
+ "width" - bin offset.
+ "count" - number of bins generated.
+ "infinity" - whether to add(-inf, inf)as start/end point in generated set of bins.
+ The above "linear_bin" descriptor generates a set of bins: [-inf, 0.0, 5.0, 10.0, 15.0, 20.0, +inf].
- - "log_bin": "{"start":1.0, "factor": 2.0, "count": 5, "infinity": true}"
- "start" - bin starting point.
- "factor" - exponential factor of bin offset.
- "count" - number of bins generated.
- "infinity" - whether to add(-inf, inf)as start/end point in generated range of bins.
- The above "log_bin" descriptor generates a set of bins:[-inf, 1.0, 2.0, 4.0, 8.0, 16.0, +inf].
+ - "log_bin": "{"start":1.0, "factor": 2.0, "count": 5, "infinity": true}"
+ "start" - bin starting point.
+ "factor" - exponential factor of bin offset.
+ "count" - number of bins generated.
+ "infinity" - whether to add(-inf, inf)as start/end point in generated range of bins.
+ The above "log_bin" descriptor generates a set of bins:[-inf, 1.0, 2.0, 4.0, 8.0, 16.0, +inf].
3. normalized: setting to 1/0 to turn on/off result normalization.
-**Example**:
+## Selector Functions
-```mysql
-taos> SELECT HISTOGRAM(voltage, "user_input", "[1,3,5,7]", 1) FROM meters;
- histogram(voltage, "user_input", "[1,3,5,7]", 1) |
- =======================================================
- {"lower_bin":1, "upper_bin":3, "count":0.333333} |
- {"lower_bin":3, "upper_bin":5, "count":0.333333} |
- {"lower_bin":5, "upper_bin":7, "count":0.333333} |
- Query OK, 3 row(s) in set (0.004273s)
+Selector functiosn choose one or more rows in the query result set to retrun according toe the semantics. You can specify to output ts column and other columns including tbname and tags so that you can easily know which rows the selected values belong to.
-taos> SELECT HISTOGRAM(voltage, 'linear_bin', '{"start": 1, "width": 3, "count": 3, "infinity": false}', 0) FROM meters;
- histogram(voltage, 'linear_bin', '{"start": 1, "width": 3, " |
- ===================================================================
- {"lower_bin":1, "upper_bin":4, "count":3} |
- {"lower_bin":4, "upper_bin":7, "count":3} |
- {"lower_bin":7, "upper_bin":10, "count":3} |
- Query OK, 3 row(s) in set (0.004887s)
-
-taos> SELECT HISTOGRAM(voltage, 'log_bin', '{"start": 1, "factor": 3, "count": 3, "infinity": true}', 0) FROM meters;
- histogram(voltage, 'log_bin', '{"start": 1, "factor": 3, "count" |
- ===================================================================
- {"lower_bin":-inf, "upper_bin":1, "count":3} |
- {"lower_bin":1, "upper_bin":3, "count":2} |
- {"lower_bin":3, "upper_bin":9, "count":6} |
- {"lower_bin":9, "upper_bin":27, "count":3} |
- {"lower_bin":27, "upper_bin":inf, "count":1} |
-```
-
-### ELAPSED
-
-```mysql
-SELECT ELAPSED(field_name[, time_unit]) FROM { tb_name | stb_name } [WHERE clause] [INTERVAL(interval [, offset]) [SLIDING sliding]];
-```
-
-**Description**:`elapsed` function can be used to calculate the continuous time length in which there is valid data. If it's used with `INTERVAL` clause, the returned result is the calcualted time length within each time window. If it's used without `INTERVAL` caluse, the returned result is the calculated time length within the specified time range. Please be noted that the return value of `elapsed` is the number of `time_unit` in the calculated time length.
-
-**Return value type**:Double
-
-**Applicable Column type**:Timestamp
-
-**Applicable versions**:Sicne version 2.6.0.0
-
-**Applicable tables**: table, STable, outter in nested query
-
-**Explanations**:
-- `field_name` parameter can only be the first column of a table, i.e. timestamp primary key.
-- The minimum value of `time_unit` is the time precision of the database. If `time_unit` is not specified, the time precision of the database is used as the default ime unit.
-- It can be used with `INTERVAL` to get the time valid time length of each time window. Please be noted that the return value is same as the time window for all time windows except for the first and the last time window.
-- `order by asc/desc` has no effect on the result.
-- `group by tbname` must be used together when `elapsed` is used against a STable.
-- `group by` must NOT be used together when `elapsed` is used against a table or sub table.
-- When used in nested query, it's only applicable when the inner query outputs an implicit timestamp column as the primary key. For example, `select elapsed(ts) from (select diff(value) from sub1)` is legal usage while `select elapsed(ts) from (select * from sub1)` is not.
-- It can't be used with `leastsquares`, `diff`, `derivative`, `top`, `bottom`, `last_row`, `interp`.
-
-## Selection Functions
-
-When any select function is used, timestamp column or tag columns including `tbname` can be specified to show that the selected value are from which rows.
-
-### MIN
+### APERCENTILE
```
-SELECT MIN(field_name) FROM {tb_name | stb_name} [WHERE clause];
+SELECT APERCENTILE(field_name, P[, algo_type])
+FROM { tb_name | stb_name } [WHERE clause]
```
-**Description**: The minimum value of a specific column in a table or STable
+**Description**: Similar to `PERCENTILE`, but a simulated result is returned
-**Return value type**: Same as the data type of the column being operated upon
+**Return value type**: Double precision floating point
-**Applicable column types**: Data types except for timestamp, binary, nchar and bool
+**Applicable column types**: Numeric types
**Applicable table types**: table, STable
-**Examples**:
+**More explanations**
+
+- _P_ is in range [0,100], when _P_ is 0, the result is same as using function MIN; when _P_ is 100, the result is same as function MAX.
+- **algo_type** can only be input as `default` or `t-digest`, if it's not specified `default` will be used, i.e. `apercentile(column_name, 50)` is same as `apercentile(column_name, 50, "default")`.
+- When `t-digest` is used, `t-digest` sampling is used to calculate.
+
+**Nested query**: It can be used in both the outer query and inner query in a nested query.
+
+### BOTTOM
```
-taos> SELECT MIN(current), MIN(voltage) FROM meters;
- min(current) | min(voltage) |
-======================================
- 10.20000 | 218 |
-Query OK, 1 row(s) in set (0.001765s)
-
-taos> SELECT MIN(current), MIN(voltage) FROM d1001;
- min(current) | min(voltage) |
-======================================
- 10.30000 | 218 |
-Query OK, 1 row(s) in set (0.000950s)
+SELECT BOTTOM(field_name, K) FROM { tb_name | stb_name } [WHERE clause];
```
-### MAX
+**Description**: The least _k_ values of a specific column in a table or STable. If a value has multiple occurrences in the column but counting all of them in will exceed the upper limit _k_, then a part of them will be returned randomly.
-```
-SELECT MAX(field_name) FROM { tb_name | stb_name } [WHERE clause];
-```
+**Return value type**: Same as the column being operated upon
-**Description**: The maximum value of a specific column of a table or STable
-
-**Return value type**: Same as the data type of the column being operated upon
-
-**Applicable column types**: Data types except for timestamp, binary, nchar and bool
+**Applicable column types**: Numeric types
**Applicable table types**: table, STable
-**Examples**:
+**More explanations**:
-```
-taos> SELECT MAX(current), MAX(voltage) FROM meters;
- max(current) | max(voltage) |
-======================================
- 13.40000 | 223 |
-Query OK, 1 row(s) in set (0.001123s)
-
-taos> SELECT MAX(current), MAX(voltage) FROM d1001;
- max(current) | max(voltage) |
-======================================
- 12.60000 | 221 |
-Query OK, 1 row(s) in set (0.000987s)
-```
+- _k_ must be in range [1,100]
+- The timestamp associated with the selected values are returned too
+- Can't be used with `FILL`
### FIRST
@@ -437,240 +865,7 @@ SELECT FIRST(field_name) FROM { tb_name | stb_name } [WHERE clause];
- NULL will be returned if all the values of the specified column are all NULL
- A result will NOT be returned if all the columns in the result set are all NULL
-**Examples**:
-
-```
-taos> SELECT FIRST(*) FROM meters;
- first(ts) | first(current) | first(voltage) | first(phase) |
-=========================================================================================
-2018-10-03 14:38:04.000 | 10.20000 | 220 | 0.23000 |
-Query OK, 1 row(s) in set (0.004767s)
-
-taos> SELECT FIRST(current) FROM d1002;
- first(current) |
-=======================
- 10.20000 |
-Query OK, 1 row(s) in set (0.001023s)
-```
-
-### LAST
-
-```
-SELECT LAST(field_name) FROM { tb_name | stb_name } [WHERE clause];
-```
-
-**Description**: The last non-NULL value of a specific column in a table or STable
-
-**Return value type**: Same as the column being operated upon
-
-**Applicable column types**: Any data type
-
-**Applicable table types**: table, STable
-
-**More explanations**:
-
-- LAST(\*) can be used to get the last non-NULL value of all columns
-- If the values of a column in the result set are all NULL, NULL is returned for that column; if all columns in the result are all NULL, no result will be returned.
-- When it's used on a STable, if there are multiple values with the timestamp in the result set, one of them will be returned randomly and it's not guaranteed that the same value is returned if the same query is run multiple times.
-
-**Examples**:
-
-```
-taos> SELECT LAST(*) FROM meters;
- last(ts) | last(current) | last(voltage) | last(phase) |
-========================================================================================
-2018-10-03 14:38:16.800 | 12.30000 | 221 | 0.31000 |
-Query OK, 1 row(s) in set (0.001452s)
-
-taos> SELECT LAST(current) FROM d1002;
- last(current) |
-=======================
- 10.30000 |
-Query OK, 1 row(s) in set (0.000843s)
-```
-
-### TOP
-
-```
-SELECT TOP(field_name, K) FROM { tb_name | stb_name } [WHERE clause];
-```
-
-**Description**: The greatest _k_ values of a specific column in a table or STable. If a value has multiple occurrences in the column but counting all of them in will exceed the upper limit _k_, then a part of them will be returned randomly.
-
-**Return value type**: Same as the column being operated upon
-
-**Applicable column types**: Data types except for timestamp, binary, nchar and bool
-
-**Applicable table types**: table, STable
-
-**More explanations**:
-
-- _k_ must be in range [1,100]
-- The timestamp associated with the selected values are returned too
-- Can't be used with `FILL`
-
-**Examples**:
-
-```
-taos> SELECT TOP(current, 3) FROM meters;
- ts | top(current, 3) |
-=================================================
-2018-10-03 14:38:15.000 | 12.60000 |
-2018-10-03 14:38:16.600 | 13.40000 |
-2018-10-03 14:38:16.800 | 12.30000 |
-Query OK, 3 row(s) in set (0.001548s)
-
-taos> SELECT TOP(current, 2) FROM d1001;
- ts | top(current, 2) |
-=================================================
-2018-10-03 14:38:15.000 | 12.60000 |
-2018-10-03 14:38:16.800 | 12.30000 |
-Query OK, 2 row(s) in set (0.000810s)
-```
-
-### BOTTOM
-
-```
-SELECT BOTTOM(field_name, K) FROM { tb_name | stb_name } [WHERE clause];
-```
-
-**Description**: The least _k_ values of a specific column in a table or STable. If a value has multiple occurrences in the column but counting all of them in will exceed the upper limit _k_, then a part of them will be returned randomly.
-
-**Return value type**: Same as the column being operated upon
-
-**Applicable column types**: Data types except for timestamp, binary, nchar and bool
-
-**Applicable table types**: table, STable
-
-**More explanations**:
-
-- _k_ must be in range [1,100]
-- The timestamp associated with the selected values are returned too
-- Can't be used with `FILL`
-
-**Examples**:
-
-```
-taos> SELECT BOTTOM(voltage, 2) FROM meters;
- ts | bottom(voltage, 2) |
-===============================================
-2018-10-03 14:38:15.000 | 218 |
-2018-10-03 14:38:16.650 | 218 |
-Query OK, 2 row(s) in set (0.001332s)
-
-taos> SELECT BOTTOM(current, 2) FROM d1001;
- ts | bottom(current, 2) |
-=================================================
-2018-10-03 14:38:05.000 | 10.30000 |
-2018-10-03 14:38:16.800 | 12.30000 |
-Query OK, 2 row(s) in set (0.000793s)
-```
-
-### PERCENTILE
-
-```
-SELECT PERCENTILE(field_name, P) FROM { tb_name } [WHERE clause];
-```
-
-**Description**: The value whose rank in a specific column matches the specified percentage. If such a value matching the specified percentage doesn't exist in the column, an interpolation value will be returned.
-
-**Return value type**: Double precision floating point
-
-**Applicable column types**: Data types except for timestamp, binary, nchar and bool
-
-**Applicable table types**: table
-
-**More explanations**: _P_ is in range [0,100], when _P_ is 0, the result is same as using function MIN; when _P_ is 100, the result is same as function MAX.
-
-**Examples**:
-
-```
-taos> SELECT PERCENTILE(current, 20) FROM d1001;
-percentile(current, 20) |
-============================
- 11.100000191 |
-Query OK, 1 row(s) in set (0.000787s)
-```
-
-### APERCENTILE
-
-```
-SELECT APERCENTILE(field_name, P[, algo_type])
-FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: Similar to `PERCENTILE`, but a simulated result is returned
-
-**Return value type**: Double precision floating point
-
-**Applicable column types**: Data types except for timestamp, binary, nchar and bool
-
-**Applicable table types**: table, STable
-
-**More explanations**
-
-- _P_ is in range [0,100], when _P_ is 0, the result is same as using function MIN; when _P_ is 100, the result is same as function MAX.
-- **algo_type** can only be input as `default` or `t-digest`, if it's not specified `default` will be used, i.e. `apercentile(column_name, 50)` is same as `apercentile(column_name, 50, "default")`.
-- When `t-digest` is used, `t-digest` sampling is used to calculate. It can be used from version 2.2.0.0.
-
-**Nested query**: It can be used in both the outer query and inner query in a nested query.
-
-```
-taos> SELECT APERCENTILE(current, 20) FROM d1001;
-apercentile(current, 20) |
-============================
- 10.300000191 |
-Query OK, 1 row(s) in set (0.000645s)
-
-taos> select apercentile (count, 80, 'default') from stb1;
- apercentile (c0, 80, 'default') |
-==================================
- 601920857.210056424 |
-Query OK, 1 row(s) in set (0.012363s)
-
-taos> select apercentile (count, 80, 't-digest') from stb1;
- apercentile (c0, 80, 't-digest') |
-===================================
- 605869120.966666579 |
-Query OK, 1 row(s) in set (0.011639s)
-```
-
-### LAST_ROW
-
-```
-SELECT LAST_ROW(field_name) FROM { tb_name | stb_name };
-```
-
-**Description**: The last row of a table or STable
-
-**Return value type**: Same as the column being operated upon
-
-**Applicable column types**: Any data type
-
-**Applicable table types**: table, STable
-
-**More explanations**:
-
-- When it's used against a STable, multiple rows with the same and largest timestamp may exist, in this case one of them is returned randomly and it's not guaranteed that the result is same if the query is run multiple times.
-- Can't be used with `INTERVAL`.
-
-**Examples**:
-
-```
- taos> SELECT LAST_ROW(current) FROM meters;
- last_row(current) |
- =======================
- 12.30000 |
- Query OK, 1 row(s) in set (0.001238s)
-
- taos> SELECT LAST_ROW(current) FROM d1002;
- last_row(current) |
- =======================
- 10.30000 |
- Query OK, 1 row(s) in set (0.001042s)
-```
-
-### INTERP [Since version 2.3.1]
+### INTERP
```
SELECT INTERP(field_name) FROM { tb_name | stb_name } [WHERE where_condition] [ RANGE(timestamp1,timestamp2) ] [EVERY(interval)] [FILL ({ VALUE | PREV | NULL | LINEAR | NEXT})];
@@ -694,91 +889,89 @@ SELECT INTERP(field_name) FROM { tb_name | stb_name } [WHERE where_condition] [
- `INTERP` can only be used to interpolate in single timeline. So it must be used with `group by tbname` when it's used on a STable. It can't be used with `GROUP BY` when it's used in the inner query of a nested query.
- The result of `INTERP` is not influenced by `ORDER BY TIMESTAMP`, which impacts the output order only..
-**Examples**: Based on the `meters` schema used throughout the documents
-
-- Single point linear interpolation between "2017-07-14 18:40:00" and "2017-07-14 18:40:00:
+### LAST
```
- taos> SELECT INTERP(current) FROM t1 RANGE('2017-7-14 18:40:00','2017-7-14 18:40:00') FILL(LINEAR);
+SELECT LAST(field_name) FROM { tb_name | stb_name } [WHERE clause];
```
-- Get original data every 5 seconds, no interpolation, between "2017-07-14 18:00:00" and "2017-07-14 19:00:00:
-
-```
- taos> SELECT INTERP(current) FROM t1 RANGE('2017-7-14 18:00:00','2017-7-14 19:00:00') EVERY(5s);
-```
-
-- Linear interpolation every 5 seconds between "2017-07-14 18:00:00" and "2017-07-14 19:00:00:
-
-```
- taos> SELECT INTERP(current) FROM t1 RANGE('2017-7-14 18:00:00','2017-7-14 19:00:00') EVERY(5s) FILL(LINEAR);
-```
-
-- Backward interpolation every 5 seconds
-
-```
- taos> SELECT INTERP(current) FROM t1 EVERY(5s) FILL(NEXT);
-```
-
-- Linear interpolation every 5 seconds between "2017-07-14 17:00:00" and "2017-07-14 20:00:00"
-
-```
- taos> SELECT INTERP(current) FROM t1 where ts >= '2017-07-14 17:00:00' and ts <= '2017-07-14 20:00:00' RANGE('2017-7-14 18:00:00','2017-7-14 19:00:00') EVERY(5s) FILL(LINEAR);
-```
-
-### INTERP [Since version 2.0.15.0]
-
-```
-SELECT INTERP(field_name) FROM { tb_name | stb_name } WHERE ts='timestamp' [FILL ({ VALUE | PREV | NULL | LINEAR | NEXT})];
-```
-
-**Description**: The value of a specific column that matches the specified time slice
+**Description**: The last non-NULL value of a specific column in a table or STable
**Return value type**: Same as the column being operated upon
-**Applicable column types**: Numeric data type
+**Applicable column types**: Any data type
**Applicable table types**: table, STable
**More explanations**:
-- Time slice must be specified. If there is no data matching the specified time slice, interpolation is performed based on `FILL` parameter. Conditions such as tags or `tbname` can be used `Where` clause can be used to filter data.
-- The timestamp specified must be within the time range of the data rows of the table or STable. If it is beyond the valid time range, nothing is returned even with `FILL` parameter.
-- `INTERP` can be used to query only single time point once. `INTERP` can be used with `EVERY` to get the interpolation value every time interval.
-- **Examples**:
+- LAST(\*) can be used to get the last non-NULL value of all columns
+- If the values of a column in the result set are all NULL, NULL is returned for that column; if all columns in the result are all NULL, no result will be returned.
+- When it's used on a STable, if there are multiple values with the timestamp in the result set, one of them will be returned randomly and it's not guaranteed that the same value is returned if the same query is run multiple times.
+
+### LAST_ROW
```
- taos> SELECT INTERP(*) FROM meters WHERE ts='2017-7-14 18:40:00.004';
- interp(ts) | interp(current) | interp(voltage) | interp(phase) |
- ==========================================================================================
- 2017-07-14 18:40:00.004 | 9.84020 | 216 | 0.32222 |
- Query OK, 1 row(s) in set (0.002652s)
+SELECT LAST_ROW(field_name) FROM { tb_name | stb_name };
```
-If there is no data corresponding to the specified timestamp, an interpolation value is returned if interpolation policy is specified by `FILL` parameter; or nothing is returned.
+**Description**: The last row of a table or STable
+
+**Return value type**: Same as the column being operated upon
+
+**Applicable column types**: Any data type
+
+**Applicable table types**: table, STable
+
+**More explanations**:
+
+- When it's used against a STable, multiple rows with the same and largest timestamp may exist, in this case one of them is returned randomly and it's not guaranteed that the result is same if the query is run multiple times.
+- Can't be used with `INTERVAL`.
+
+### MAX
```
- taos> SELECT INTERP(*) FROM meters WHERE tbname IN ('d636') AND ts='2017-7-14 18:40:00.005';
- Query OK, 0 row(s) in set (0.004022s)
-
- taos> SELECT INTERP(*) FROM meters WHERE tbname IN ('d636') AND ts='2017-7-14 18:40:00.005' FILL(PREV);
- interp(ts) | interp(current) | interp(voltage) | interp(phase) |
- ==========================================================================================
- 2017-07-14 18:40:00.005 | 9.88150 | 217 | 0.32500 |
- Query OK, 1 row(s) in set (0.003056s)
+SELECT MAX(field_name) FROM { tb_name | stb_name } [WHERE clause];
```
-Interpolation is performed every 5 milliseconds between `['2017-7-14 18:40:00', '2017-7-14 18:40:00.014']`
+**Description**: The maximum value of a specific column of a table or STable
+
+**Return value type**: Same as the data type of the column being operated upon
+
+**Applicable column types**: Numeric types
+
+**Applicable table types**: table, STable
+
+### MIN
```
- taos> SELECT INTERP(current) FROM d636 WHERE ts>='2017-7-14 18:40:00' AND ts<='2017-7-14 18:40:00.014' EVERY(5a);
- ts | interp(current) |
- =================================================
- 2017-07-14 18:40:00.000 | 10.04179 |
- 2017-07-14 18:40:00.010 | 10.16123 |
- Query OK, 2 row(s) in set (0.003487s)
+SELECT MIN(field_name) FROM {tb_name | stb_name} [WHERE clause];
```
+**Description**: The minimum value of a specific column in a table or STable
+
+**Return value type**: Same as the data type of the column being operated upon
+
+**Applicable column types**: Numeric types
+
+**Applicable table types**: table, STable
+
+### PERCENTILE
+
+```
+SELECT PERCENTILE(field_name, P) FROM { tb_name } [WHERE clause];
+```
+
+**Description**: The value whose rank in a specific column matches the specified percentage. If such a value matching the specified percentage doesn't exist in the column, an interpolation value will be returned.
+
+**Return value type**: Double precision floating point
+
+**Applicable column types**: Numeric types
+
+**Applicable table types**: table
+
+**More explanations**: _P_ is in range [0,100], when _P_ is 0, the result is same as using function MIN; when _P_ is 100, the result is same as function MAX.
+
### TAIL
```
@@ -793,30 +986,26 @@ SELECT TAIL(field_name, k, offset_val) FROM {tb_name | stb_name} [WHERE clause];
**Applicable column types**: Any data type except form timestamp, i.e. the primary key
-**Applicable versions**: Since version 2.6.0.0
-
-**Examples**:
+### TOP
```
-taos> select ts,dbig from tail2;
- ts | dbig |
-==================================================
-2021-10-15 00:31:33.000 | 1 |
-2021-10-17 00:31:31.000 | NULL |
-2021-12-24 00:31:34.000 | 2 |
-2022-01-01 08:00:05.000 | 19 |
-2022-01-01 08:00:06.000 | NULL |
-2022-01-01 08:00:07.000 | 9 |
-Query OK, 6 row(s) in set (0.001952s)
-
-taos> select tail(dbig,2,2) from tail2;
-ts | tail(dbig,2,2) |
-==================================================
-2021-12-24 00:31:34.000 | 2 |
-2022-01-01 08:00:05.000 | 19 |
-Query OK, 2 row(s) in set (0.002307s)
+SELECT TOP(field_name, K) FROM { tb_name | stb_name } [WHERE clause];
```
+**Description**: The greatest _k_ values of a specific column in a table or STable. If a value has multiple occurrences in the column but counting all of them in will exceed the upper limit _k_, then a part of them will be returned randomly.
+
+**Return value type**: Same as the column being operated upon
+
+**Applicable column types**: Numeric types
+
+**Applicable table types**: table, STable
+
+**More explanations**:
+
+- _k_ must be in range [1,100]
+- The timestamp associated with the selected values are returned too
+- Can't be used with `FILL`
+
### UNIQUE
```
@@ -829,179 +1018,14 @@ SELECT UNIQUE(field_name) FROM {tb_name | stb_name} [WHERE clause];
**Applicable column types**: Any data types except for timestamp
-**Applicable versions**: Since version 2.6.0.0
-
**More explanations**:
- It can be used against table or STable, but can't be used together with time window, like `interval`, `state_window` or `session_window` .
- Considering the number of result sets is unpredictable, it's suggested to limit the distinct values under 100,000 to control the memory usage, otherwise error will be returned.
-**Examples**:
+## Time-Series Specific Functions
-```
-taos> select ts,voltage from unique1;
- ts | voltage |
-==================================================
-2021-10-17 00:31:31.000 | 1 |
-2022-01-24 00:31:31.000 | 1 |
-2021-10-17 00:31:31.000 | 1 |
-2021-12-24 00:31:31.000 | 2 |
-2022-01-01 08:00:01.000 | 19 |
-2021-10-17 00:31:31.000 | NULL |
-2022-01-01 08:00:02.000 | NULL |
-2022-01-01 08:00:03.000 | 9 |
-Query OK, 8 row(s) in set (0.003018s)
-
-taos> select unique(voltage) from unique1;
-ts | unique(voltage) |
-==================================================
-2021-10-17 00:31:31.000 | 1 |
-2021-10-17 00:31:31.000 | NULL |
-2021-12-24 00:31:31.000 | 2 |
-2022-01-01 08:00:01.000 | 19 |
-2022-01-01 08:00:03.000 | 9 |
-Query OK, 5 row(s) in set (0.108458s)
-```
-
-## Scalar functions
-
-### DIFF
-
-```sql
-SELECT {DIFF(field_name, ignore_negative) | DIFF(field_name)} FROM tb_name [WHERE clause];
-```
-
-**Description**: The different of each row with its previous row for a specific column. `ignore_negative` can be specified as 0 or 1, the default value is 1 if it's not specified. `1` means negative values are ignored.
-
-**Return value type**: Same as the column being operated upon
-
-**Applicable column types**: Data types except for timestamp, binary, nchar and bool
-
-**Applicable table types**: table, STable
-
-**More explanations**:
-
-- The number of result rows is the number of rows subtracted by one, no output for the first row
-- Since version 2.1.30, `DIFF` can be used on STable with `GROUP by tbname`
-- Since version 2.6.0, `ignore_negative` parameter is supported
-
-**Examples**:
-
-```sql
-taos> SELECT DIFF(current) FROM d1001;
- ts | diff(current) |
-=================================================
-2018-10-03 14:38:15.000 | 2.30000 |
-2018-10-03 14:38:16.800 | -0.30000 |
-Query OK, 2 row(s) in set (0.001162s)
-```
-
-### DERIVATIVE
-
-```
-SELECT DERIVATIVE(field_name, time_interval, ignore_negative) FROM tb_name [WHERE clause];
-```
-
-**Description**: The derivative of a specific column. The time rage can be specified by parameter `time_interval`, the minimum allowed time range is 1 second (1s); the value of `ignore_negative` can be 0 or 1, 1 means negative values are ignored.
-
-**Return value type**: Double precision floating point
-
-**Applicable column types**: Data types except for timestamp, binary, nchar and bool
-
-**Applicable table types**: table, STable
-
-**More explanations**:
-
-- It is available from version 2.1.3.0, the number of result rows is the number of total rows in the time range subtracted by one, no output for the first row.
-- It can be used together with `GROUP BY tbname` against a STable.
-
-**Examples**:
-
-```
-taos> select derivative(current, 10m, 0) from t1;
- ts | derivative(current, 10m, 0) |
-========================================================
- 2021-08-20 10:11:22.790 | 0.500000000 |
- 2021-08-20 11:11:22.791 | 0.166666620 |
- 2021-08-20 12:11:22.791 | 0.000000000 |
- 2021-08-20 13:11:22.792 | 0.166666620 |
- 2021-08-20 14:11:22.792 | -0.666666667 |
-Query OK, 5 row(s) in set (0.004883s)
-```
-
-### SPREAD
-
-```
-SELECT SPREAD(field_name) FROM { tb_name | stb_name } [WHERE clause];
-```
-
-**Description**: The difference between the max and the min of a specific column
-
-**Return value type**: Double precision floating point
-
-**Applicable column types**: Data types except for binary, nchar, and bool
-
-**Applicable table types**: table, STable
-
-**More explanations**: Can be used on a column of TIMESTAMP type, the result is the time range size.
-
-**Examples**:
-
-```
-taos> SELECT SPREAD(voltage) FROM meters;
- spread(voltage) |
-============================
- 5.000000000 |
-Query OK, 1 row(s) in set (0.001792s)
-
-taos> SELECT SPREAD(voltage) FROM d1001;
- spread(voltage) |
-============================
- 3.000000000 |
-Query OK, 1 row(s) in set (0.000836s)
-```
-
-### CEIL
-
-```
-SELECT CEIL(field_name) FROM { tb_name | stb_name } [WHERE clause];
-```
-
-**Description**: The rounded up value of a specific column
-
-**Return value type**: Same as the column being used
-
-**Applicable data types**: Data types except for timestamp, binary, nchar, bool
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and outer query
-
-**More explanations**:
-
-- Can't be used on any tags of any type
-- Arithmetic operation can be performed on the result of `ceil` function
-- Can't be used with aggregate functions
-
-### FLOOR
-
-```
-SELECT FLOOR(field_name) FROM { tb_name | stb_name } [WHERE clause];
-```
-
-**Description**: The rounded down value of a specific column
-
-**More explanations**: The restrictions are same as those of the `CEIL` function.
-
-### ROUND
-
-```
-SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
-```
-
-**Description**: The rounded value of a specific column.
-
-**More explanations**: The restrictions are same as `CEIL` function.
+TDengine provides a set of time-series specific functions to better meet the requirements in querying time-series data. In general databases, similar functionalities can only be achieved with much more complex syntax and much worse performance. TDengine provides these functionalities in builtin functions so that the burden on user side is minimized.
### CSUM
@@ -1013,20 +1037,72 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
**Return value type**: Long integer for integers; Double for floating points. Timestamp is returned for each row.
-**Applicable data types**: Data types except for timestamp, binary, nchar, and bool
+**Applicable data types**: Numeric types
**Applicable table types**: table, STable
**Applicable nested query**: Inner query and Outer query
**More explanations**:
-
-- Can't be used on tags when it's used on STable
- Arithmetic operation can't be performed on the result of `csum` function
- Can only be used with aggregate functions
- `Group by tbname` must be used together on a STable to force the result on a single timeline
-**Applicable versions**: Since 2.3.0.x
+### DERIVATIVE
+
+```
+SELECT DERIVATIVE(field_name, time_interval, ignore_negative) FROM tb_name [WHERE clause];
+```
+
+**Description**: The derivative of a specific column. The time rage can be specified by parameter `time_interval`, the minimum allowed time range is 1 second (1s); the value of `ignore_negative` can be 0 or 1, 1 means negative values are ignored.
+
+**Return value type**: Double precision floating point
+
+**Applicable column types**: Numeric types
+
+**Applicable table types**: table, STable
+
+**More explanations**:
+
+- The number of result rows is the number of total rows in the time range subtracted by one, no output for the first row.
+- It can be used together with `GROUP BY tbname` against a STable.
+
+### DIFF
+
+```sql
+SELECT {DIFF(field_name, ignore_negative) | DIFF(field_name)} FROM tb_name [WHERE clause];
+```
+
+**Description**: The different of each row with its previous row for a specific column. `ignore_negative` can be specified as 0 or 1, the default value is 1 if it's not specified. `1` means negative values are ignored.
+
+**Return value type**: Same as the column being operated upon
+
+**Applicable column types**: Numeric types
+
+**Applicable table types**: table, STable
+
+**More explanations**:
+
+- The number of result rows is the number of rows subtracted by one, no output for the first row
+- It can be used on STable with `GROUP by tbname`
+
+### IRATE
+
+```
+SELECT IRATE(field_name) FROM tb_name WHERE clause;
+```
+
+**Description**: instantaneous rate on a specific column. The last two samples in the specified time range are used to calculate instantaneous rate. If the last sample value is smaller, then only the last sample value is used instead of the difference between the last two sample values.
+
+**Return value type**: Double precision floating number
+
+**Applicable column types**: Numeric types
+
+**Applicable table types**: table, STable
+
+**More explanations**:
+
+- It can be used on stble with `GROUP BY`, i.e. timelines generated by `GROUP BY tbname` on a STable.
### MAVG
@@ -1034,11 +1110,11 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
SELECT MAVG(field_name, K) FROM { tb_name | stb_name } [WHERE clause]
```
-**Description**: The moving average of continuous _k_ values of a specific column. If the number of input rows is less than _k_, nothing is returned. The applicable range is _k_ is [1,1000].
+**Description**: The moving average of continuous _k_ values of a specific column. If the number of input rows is less than _k_, nothing is returned. The applicable range of _k_ is [1,1000].
**Return value type**: Double precision floating point
-**Applicable data types**: Data types except for timestamp, binary, nchar, and bool
+**Applicable data types**: Numeric types
**Applicable nested query**: Inner query and Outer query
@@ -1047,12 +1123,9 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
**More explanations**:
- Arithmetic operation can't be performed on the result of `MAVG`.
-- Can only be used with data columns, can't be used with tags.
- Can't be used with aggregate functions.
- Must be used with `GROUP BY tbname` when it's used on a STable to force the result on each single timeline.
-**Applicable versions**: Since 2.3.0.x
-
### SAMPLE
```sql
@@ -1074,469 +1147,6 @@ SELECT ROUND(field_name) FROM { tb_name | stb_name } [WHERE clause];
- Arithmetic operation can't be operated on the result of `SAMPLE` function
- Must be used with `Group by tbname` when it's used on a STable to force the result on each single timeline
-**Applicable versions**: Since 2.3.0.x
-
-### ASIN
-
-```sql
-SELECT ASIN(field_name) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: The anti-sine of a specific column
-
-**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
-
-**Applicable data types**: Data types except for timestamp, binary, nchar, bool
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**:
-
-- Can't be used with tags
-- Can't be used with aggregate functions
-
-### ACOS
-
-```sql
-SELECT ACOS(field_name) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: The anti-cosine of a specific column
-
-**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
-
-**Applicable data types**: Data types except for timestamp, binary, nchar, bool
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**:
-
-- Can't be used with tags
-- Can't be used with aggregate functions
-
-### ATAN
-
-```sql
-SELECT ATAN(field_name) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: anti-tangent of a specific column
-
-**Description**: The anti-cosine of a specific column
-
-**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
-
-**Applicable data types**: Data types except for timestamp, binary, nchar, bool
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**:
-
-- Can't be used with tags
-- Can't be used with aggregate functions
-
-### SIN
-
-```sql
-SELECT SIN(field_name) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: The sine of a specific column
-
-**Description**: The anti-cosine of a specific column
-
-**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
-
-**Applicable data types**: Data types except for timestamp, binary, nchar, bool
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**:
-
-- Can't be used with tags
-- Can't be used with aggregate functions
-
-### COS
-
-```sql
-SELECT COS(field_name) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: The cosine of a specific column
-
-**Description**: The anti-cosine of a specific column
-
-**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
-
-**Applicable data types**: Data types except for timestamp, binary, nchar, bool
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**:
-
-- Can't be used with tags
-- Can't be used with aggregate functions
-
-### TAN
-
-```sql
-SELECT TAN(field_name) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: The tangent of a specific column
-
-**Description**: The anti-cosine of a specific column
-
-**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
-
-**Applicable data types**: Data types except for timestamp, binary, nchar, bool
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**:
-
-- Can't be used with tags
-- Can't be used with aggregate functions
-
-### POW
-
-```sql
-SELECT POW(field_name, power) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: The power of a specific column with `power` as the index
-
-**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
-
-**Applicable data types**: Data types except for timestamp, binary, nchar, bool
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**:
-
-- Can't be used with tags
-- Can't be used with aggregate functions
-
-### LOG
-
-```sql
-SELECT LOG(field_name, base) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: The log of a specific with `base` as the radix
-
-**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
-
-**Applicable data types**: Data types except for timestamp, binary, nchar, bool
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**:
-
-- Can't be used with tags
-- Can't be used with aggregate functions
-
-### ABS
-
-```sql
-SELECT ABS(field_name) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: The absolute of a specific column
-
-**Return value type**: UBIGINT if the input value is integer; DOUBLE if the input value is FLOAT/DOUBLE
-
-**Applicable data types**: Data types except for timestamp, binary, nchar, bool
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**:
-
-- Can't be used with tags
-- Can't be used with aggregate functions
-
-### SQRT
-
-```sql
-SELECT SQRT(field_name) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: The square root of a specific column
-
-**Return value type**: Double if the input value is not NULL; or NULL if the input value is NULL
-
-**Applicable data types**: Data types except for timestamp, binary, nchar, bool
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**:
-
-- Can't be used with tags
-- Can't be used with aggregate functions
-
-### CAST
-
-```sql
-SELECT CAST(expression AS type_name) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: It's used for type casting. The input parameter `expression` can be data columns, constants, scalar functions or arithmetic between them. Can't be used with tags, and can only be used in `select` clause.
-
-**Return value type**: The type specified by parameter `type_name`
-
-**Applicable data types**:
-
-- Parameter `expression` can be any data type except for JSON, more specifically it can be any of BOOL/TINYINT/SMALLINT/INT/BIGINT/FLOAT/DOUBLE/BINARY(M)/TIMESTAMP/NCHAR(M)/TINYINT UNSIGNED/SMALLINT UNSIGNED/INT UNSIGNED/BIGINT UNSIGNED
-- The output data type specified by `type_name` can only be one of BIGINT/BINARY(N)/TIMESTAMP/NCHAR(N)/BIGINT UNSIGNED
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**:
-
-- Error will be reported for unsupported type casting
-- NULL will be returned if the input value is NULL
-- Some values of some supported data types may not be casted, below are known issues:
- 1)When casting BINARY/NCHAR to BIGINT/BIGINT UNSIGNED, some characters may be treated as illegal, for example "a" may be converted to 0.
- 2)There may be overflow when casting singed integer or TIMESTAMP to unsigned BIGINT
- 3)There may be overflow when casting unsigned BIGINT to BIGINT
- 4)There may be overflow when casting FLOAT/DOUBLE to BIGINT or UNSIGNED BIGINT
-
-### CONCAT
-
-```sql
-SELECT CONCAT(str1|column1, str2|column2, ...) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: The concatenation result of two or more strings, the number of strings to be concatenated is at least 2 and at most 8
-
-**Return value type**: Same as the columns being operated, BINARY or NCHAR; or NULL if all the input are NULL
-
-**Applicable data types**: The input data must be in either all BINARY or in all NCHAR; can't be used on tag columns
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-### CONCAT_WS
-
-```
-SELECT CONCAT_WS(separator, str1|column1, str2|column2, ...) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: The concatenation result of two or more strings with separator, the number of strings to be concatenated is at least 3 and at most 9
-
-**Return value type**: Same as the columns being operated, BINARY or NCHAR; or NULL if all the input are NULL
-
-**Applicable data types**: The input data must be in either all BINARY or in all NCHAR; can't be used on tag columns
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**:
-
-- If the value of `separator` is NULL, the output is NULL. If the value of `separator` is not NULL but other input are all NULL, the output is empty string.
-
-### LENGTH
-
-```
-SELECT LENGTH(str|column) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: The length in bytes of a string
-
-**Return value type**: Integer
-
-**Applicable data types**: BINARY or NCHAR, can't be used on tags
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**
-
-- If the input value is NULL, the output is NULL too
-
-### CHAR_LENGTH
-
-```
-SELECT CHAR_LENGTH(str|column) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: The length in number of characters of a string
-
-**Return value type**: Integer
-
-**Applicable data types**: BINARY or NCHAR, can't be used on tags
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**
-
-- If the input value is NULL, the output is NULL too
-
-### LOWER
-
-```
-SELECT LOWER(str|column) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: Convert the input string to lower case
-
-**Return value type**: Same as input
-
-**Applicable data types**: BINARY or NCHAR, can't be used on tags
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**
-
-- If the input value is NULL, the output is NULL too
-
-### UPPER
-
-```
-SELECT UPPER(str|column) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: Convert the input string to upper case
-
-**Return value type**: Same as input
-
-**Applicable data types**: BINARY or NCHAR, can't be used on tags
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**
-
-- If the input value is NULL, the output is NULL too
-
-### LTRIM
-
-```
-SELECT LTRIM(str|column) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: Remove the left leading blanks of a string
-
-**Return value type**: Same as input
-
-**Applicable data types**: BINARY or NCHAR, can't be used on tags
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**
-
-- If the input value is NULL, the output is NULL too
-
-### RTRIM
-
-```
-SELECT RTRIM(str|column) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: Remove the right tailing blanks of a string
-
-**Return value type**: Same as input
-
-**Applicable data types**: BINARY or NCHAR, can't be used on tags
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**
-
-- If the input value is NULL, the output is NULL too
-
-### SUBSTR
-
-```
-SELECT SUBSTR(str,pos[,len]) FROM { tb_name | stb_name } [WHERE clause]
-```
-
-**Description**: The sub-string starting from `pos` with length of `len` from the original string `str`
-
-**Return value type**: Same as input
-
-**Applicable data types**: BINARY or NCHAR, can't be used on tags
-
-**Applicable table types**: table, STable
-
-**Applicable nested query**: Inner query and Outer query
-
-**Applicable versions**: From 2.6.0.0
-
-**More explanations**:
-
-- If the input is NULL, the output is NULL
-- Parameter `pos` can be an positive or negative integer; If it's positive, the starting position will be counted from the beginning of the string; if it's negative, the starting position will be counted from the end of the string.
-- If `len` is not specified, it means from `pos` to the end.
-
### STATECOUNT
```
@@ -1552,45 +1162,17 @@ SELECT STATECOUNT(field_name, oper, val) FROM { tb_name | stb_name } [WHERE clau
**Return value type**: Integer
-**Applicable data types**: Data types excpet for timestamp, binary, nchar, bool
+**Applicable data types**: Numeric types
**Applicable table types**: table, STable
**Applicable nested query**: Outer query only
-**Applicable versions**: From 2.6.0.0
-
**More explanations**:
- Must be used together with `GROUP BY tbname` when it's used on a STable to force the result into each single timeline]
- Can't be used with window operation, like interval/state_window/session_window
-**Examples**:
-
-```
-taos> select ts,dbig from statef2;
- ts | dbig |
-========================================================
-2021-10-15 00:31:33.000000000 | 1 |
-2021-10-17 00:31:31.000000000 | NULL |
-2021-12-24 00:31:34.000000000 | 2 |
-2022-01-01 08:00:05.000000000 | 19 |
-2022-01-01 08:00:06.000000000 | NULL |
-2022-01-01 08:00:07.000000000 | 9 |
-Query OK, 6 row(s) in set (0.002977s)
-
-taos> select stateCount(dbig,GT,2) from statef2;
-ts | dbig | statecount(dbig,gt,2) |
-================================================================================
-2021-10-15 00:31:33.000000000 | 1 | -1 |
-2021-10-17 00:31:31.000000000 | NULL | NULL |
-2021-12-24 00:31:34.000000000 | 2 | -1 |
-2022-01-01 08:00:05.000000000 | 19 | 1 |
-2022-01-01 08:00:06.000000000 | NULL | NULL |
-2022-01-01 08:00:07.000000000 | 9 | 2 |
-Query OK, 6 row(s) in set (0.002791s)
-```
-
### STATEDURATION
```
@@ -1607,326 +1189,65 @@ SELECT stateDuration(field_name, oper, val, unit) FROM { tb_name | stb_name } [W
**Return value type**: Integer
-**Applicable data types**: Data types excpet for timestamp, binary, nchar, bool
+**Applicable data types**: Numeric types
**Applicable table types**: table, STable
**Applicable nested query**: Outer query only
-**Applicable versions**: From 2.6.0.0
-
**More explanations**:
- Must be used together with `GROUP BY tbname` when it's used on a STable to force the result into each single timeline]
- Can't be used with window operation, like interval/state_window/session_window
-**Examples**:
+### TWA
```
-taos> select ts,dbig from statef2;
- ts | dbig |
-========================================================
-2021-10-15 00:31:33.000000000 | 1 |
-2021-10-17 00:31:31.000000000 | NULL |
-2021-12-24 00:31:34.000000000 | 2 |
-2022-01-01 08:00:05.000000000 | 19 |
-2022-01-01 08:00:06.000000000 | NULL |
-2022-01-01 08:00:07.000000000 | 9 |
-Query OK, 6 row(s) in set (0.002407s)
-
-taos> select stateDuration(dbig,GT,2) from statef2;
-ts | dbig | stateduration(dbig,gt,2) |
-===================================================================================
-2021-10-15 00:31:33.000000000 | 1 | -1 |
-2021-10-17 00:31:31.000000000 | NULL | NULL |
-2021-12-24 00:31:34.000000000 | 2 | -1 |
-2022-01-01 08:00:05.000000000 | 19 | 0 |
-2022-01-01 08:00:06.000000000 | NULL | NULL |
-2022-01-01 08:00:07.000000000 | 9 | 2 |
-Query OK, 6 row(s) in set (0.002613s)
+SELECT TWA(field_name) FROM tb_name WHERE clause;
```
-## Time Functions
+**Description**: Time weighted average on a specific column within a time range
-Since version 2.6.0.0, below time related functions can be used in TDengine.
+**Return value type**: Double precision floating number
-### NOW
-
-```sql
-SELECT NOW() FROM { tb_name | stb_name } [WHERE clause];
-SELECT select_expr FROM { tb_name | stb_name } WHERE ts_col cond_operatior NOW();
-INSERT INTO tb_name VALUES (NOW(), ...);
-```
-
-**Description**: The current time of the client side system
-
-**Return value type**: TIMESTAMP
-
-**Applicable column types**: TIMESTAMP only
+**Applicable column types**: Numeric types
**Applicable table types**: table, STable
**More explanations**:
-- Add and Subtract operation can be performed, for example NOW() + 1s, the time unit can be:
- b(nanosecond), u(microsecond), a(millisecond)), s(second), m(minute), h(hour), d(day), w(week)
-- The precision of the returned timestamp is same as the precision set for the current data base in use
+- It can be used on stable with `GROUP BY`, i.e. timelines generated by `GROUP BY tbname` on a STable.
-**Examples**:
+## System Information Functions
-```sql
-taos> SELECT NOW() FROM meters;
- now() |
-==========================
- 2022-02-02 02:02:02.456 |
-Query OK, 1 row(s) in set (0.002093s)
+### DATABASE
-taos> SELECT NOW() + 1h FROM meters;
- now() + 1h |
-==========================
- 2022-02-02 03:02:02.456 |
-Query OK, 1 row(s) in set (0.002093s)
-
-taos> SELECT COUNT(voltage) FROM d1001 WHERE ts < NOW();
- count(voltage) |
-=============================
- 5 |
-Query OK, 5 row(s) in set (0.004475s)
-
-taos> INSERT INTO d1001 VALUES (NOW(), 10.2, 219, 0.32);
-Query OK, 1 of 1 row(s) in database (0.002210s)
+```
+SELECT DATABASE();
```
-### TODAY
+**Description**:Return the current database being used. If the user doesn't specify database when logon and doesn't use `USE` SQL command to switch the datbase, this function returns NULL.
-```sql
-SELECT TODAY() FROM { tb_name | stb_name } [WHERE clause];
-SELECT select_expr FROM { tb_name | stb_name } WHERE ts_col cond_operatior TODAY()];
-INSERT INTO tb_name VALUES (TODAY(), ...);
+### CLIENT_VERSION
+
+```
+SELECT CLIENT_VERSION();
```
-**Description**: The timestamp of 00:00:00 of the client side system
+**Description**:Return the client version.
-**Return value type**: TIMESTAMP
+### SERVER_VERSION
-**Applicable column types**: TIMESTAMP only
-
-**Applicable table types**: table, STable
-
-**More explanations**:
-
-- Add and Subtract operation can be performed, for example NOW() + 1s, the time unit can be:
- b(nanosecond), u(microsecond), a(millisecond)), s(second), m(minute), h(hour), d(day), w(week)
-- The precision of the returned timestamp is same as the precision set for the current data base in use
-
-**Examples**:
-
-```sql
-taos> SELECT TODAY() FROM meters;
- today() |
-==========================
- 2022-02-02 00:00:00.000 |
-Query OK, 1 row(s) in set (0.002093s)
-
-taos> SELECT TODAY() + 1h FROM meters;
- today() + 1h |
-==========================
- 2022-02-02 01:00:00.000 |
-Query OK, 1 row(s) in set (0.002093s)
-
-taos> SELECT COUNT(voltage) FROM d1001 WHERE ts < TODAY();
- count(voltage) |
-=============================
- 5 |
-Query OK, 5 row(s) in set (0.004475s)
-
-taos> INSERT INTO d1001 VALUES (TODAY(), 10.2, 219, 0.32);
-Query OK, 1 of 1 row(s) in database (0.002210s)
+```
+SELECT SERVER_VERSION();
```
-### TIMEZONE
+**Description**:Returns the server version.
-```sql
-SELECT TIMEZONE() FROM { tb_name | stb_name } [WHERE clause];
+### SERVER_STATUS
+
+```
+SELECT SERVER_VERSION();
```
-**Description**: The timezone of the client side system
-
-**Return value type**: BINARY
-
-**Applicable column types**: None
-
-**Applicable table types**: table, STable
-
-**Examples**:
-
-```sql
-taos> SELECT TIMEZONE() FROM meters;
- timezone() |
-=================================
- UTC (UTC, +0000) |
-Query OK, 1 row(s) in set (0.002093s)
-```
-
-### TO_ISO8601
-
-```sql
-SELECT TO_ISO8601(ts_val | ts_col) FROM { tb_name | stb_name } [WHERE clause];
-```
-
-**Description**: The ISO8601 date/time format converted from a UNIX timestamp, plus the timezone of the client side system
-
-**Return value type**: BINARY
-
-**Applicable column types**: TIMESTAMP, constant or a column
-
-**Applicable table types**: table, STable
-
-**More explanations**:
-
-- If the input is UNIX timestamp constant, the precision of the returned value is determined by the digits of the input timestamp
-- If the input is a column of TIMESTAMP type, The precision of the returned value is same as the precision set for the current data base in use
-
-**Examples**:
-
-```sql
-taos> SELECT TO_ISO8601(1643738400) FROM meters;
- to_iso8601(1643738400) |
-==============================
- 2022-02-02T02:00:00+0800 |
-
-taos> SELECT TO_ISO8601(ts) FROM meters;
- to_iso8601(ts) |
-==============================
- 2022-02-02T02:00:00+0800 |
- 2022-02-02T02:00:00+0800 |
- 2022-02-02T02:00:00+0800 |
-```
-
-### TO_UNIXTIMESTAMP
-
-```sql
-SELECT TO_UNIXTIMESTAMP(datetime_string | ts_col) FROM { tb_name | stb_name } [WHERE clause];
-```
-
-**Description**: UNIX timestamp converted from a string of date/time format
-
-**Return value type**: Long integer
-
-**Applicable column types**: Constant or column of BINARY/NCHAR
-
-**Applicable table types**: table, STable
-
-**More explanations**:
-
-- The input string must be compatible with ISO8601/RFC3339 standard, 0 will be returned if the string can't be converted
-- The precision of the returned timestamp is same as the precision set for the current data base in use
-
-**Examples**:
-
-```sql
-taos> SELECT TO_UNIXTIMESTAMP("2022-02-02T02:00:00.000Z") FROM meters;
-to_unixtimestamp("2022-02-02T02:00:00.000Z") |
-==============================================
- 1643767200000 |
-
-taos> SELECT TO_UNIXTIMESTAMP(col_binary) FROM meters;
- to_unixtimestamp(col_binary) |
-========================================
- 1643767200000 |
- 1643767200000 |
- 1643767200000 |
-```
-
-### TIMETRUNCATE
-
-```sql
-SELECT TIMETRUNCATE(ts_val | datetime_string | ts_col, time_unit) FROM { tb_name | stb_name } [WHERE clause];
-```
-
-**Description**: Truncate the input timestamp with unit specified by `time_unit`\
-
-**Return value type**: TIMESTAMP\
-
-**Applicable column types**: UNIX timestamp constant, string constant of date/time format, or a column of timestamp
-
-**Applicable table types**: table, STable
-
-**More explanations**:
-
-- Time unit specified by `time_unit` can be:
- 1u(microsecond),1a(millisecond),1s(second),1m(minute),1h(hour),1d(day).
-- The precision of the returned timestamp is same as the precision set for the current data base in use
-
-**Examples**:
-
-```sql
-taos> SELECT TIMETRUNCATE(1643738522000, 1h) FROM meters;
- timetruncate(1643738522000, 1h) |
-===================================
- 2022-02-02 02:00:00.000 |
-Query OK, 1 row(s) in set (0.001499s)
-
-taos> SELECT TIMETRUNCATE("2022-02-02 02:02:02", 1h) FROM meters;
- timetruncate("2022-02-02 02:02:02", 1h) |
-===========================================
- 2022-02-02 02:00:00.000 |
-Query OK, 1 row(s) in set (0.003903s)
-
-taos> SELECT TIMETRUNCATE(ts, 1h) FROM meters;
- timetruncate(ts, 1h) |
-==========================
- 2022-02-02 02:00:00.000 |
- 2022-02-02 02:00:00.000 |
- 2022-02-02 02:00:00.000 |
-Query OK, 3 row(s) in set (0.003903s)
-```
-
-### TIMEDIFF
-
-```sql
-SELECT TIMEDIFF(ts_val1 | datetime_string1 | ts_col1, ts_val2 | datetime_string2 | ts_col2 [, time_unit]) FROM { tb_name | stb_name } [WHERE clause];
-```
-
-**Description**: The difference between two timestamps, and rounded to the time unit specified by `time_unit`
-
-**Return value type**: Long Integer
-
-**Applicable column types**: UNIX timestamp constant, string constant of date/time format, or a column of TIMESTAMP type
-
-**Applicable table types**: table, STable
-
-**More explanations**:
-
-- Time unit specified by `time_unit` can be:
- 1u(microsecond),1a(millisecond),1s(second),1m(minute),1h(hour),1d(day).
-- The precision of the returned timestamp is same as the precision set for the current data base in use
-
-**Applicable versions**:Since version 2.6.0.0
-
-**Examples**:
-
-```sql
-taos> SELECT TIMEDIFF(1643738400000, 1643742000000) FROM meters;
- timediff(1643738400000, 1643742000000) |
-=========================================
- 3600000 |
-Query OK, 1 row(s) in set (0.002553s)
-taos> SELECT TIMEDIFF(1643738400000, 1643742000000, 1h) FROM meters;
- timediff(1643738400000, 1643742000000, 1h) |
-=============================================
- 1 |
-Query OK, 1 row(s) in set (0.003726s)
-
-taos> SELECT TIMEDIFF("2022-02-02 03:00:00", "2022-02-02 02:00:00", 1h) FROM meters;
- timediff("2022-02-02 03:00:00", "2022-02-02 02:00:00", 1h) |
-=============================================================
- 1 |
-Query OK, 1 row(s) in set (0.001937s)
-
-taos> SELECT TIMEDIFF(ts_col1, ts_col2, 1h) FROM meters;
- timediff(ts_col1, ts_col2, 1h) |
-===================================
- 1 |
-Query OK, 1 row(s) in set (0.001937s)
-```
+**Description**:Returns the server's status.
diff --git a/docs-en/12-taos-sql/13-operators.md b/docs-en/12-taos-sql/13-operators.md
index e393c82c76..0ca9ec4943 100644
--- a/docs-en/12-taos-sql/13-operators.md
+++ b/docs-en/12-taos-sql/13-operators.md
@@ -35,8 +35,8 @@ TDengine provides 2 set operators: `UNION ALL` and `UNION`. `UNION ALL` combines
| --- | :---------------: | ------------------------------------------------------------------- | ----------------------------------------------- |
| 1 | = | Except for BLOB, MEDIUMBLOB and JSON | Equal |
| 2 | <\>, != | Except for BLOB, MEDIUMBLOB, JSON and primary key of timestamp type | Not equal |
-| 3 | \>, \< | Except for BLOB, MEDIUMBLOB and JSON | Greater than, less than |
-| 4 | \>=, \<= | Except for BLOB, MEDIUMBLOB and JSON | Greater than or equal to, less than or equal to |
+| 3 | \>, < | Except for BLOB, MEDIUMBLOB and JSON | Greater than, less than |
+| 4 | \>=, <= | Except for BLOB, MEDIUMBLOB and JSON | Greater than or equal to, less than or equal to |
| 5 | IS [NOT] NULL | Any types | Is NULL or NOT |
| 6 | [NOT] BETWEEN AND | Except for BLOB, MEDIUMBLOB and JSON | In a value range or not |
| 7 | IN | Except for BLOB, MEDIUMBLOB, JSON and primary key of timestamp type | In a list of values or not |
diff --git a/docs-en/14-reference/03-connector/cpp.mdx b/docs-en/14-reference/03-connector/cpp.mdx
index d13a74384c..d549413012 100644
--- a/docs-en/14-reference/03-connector/cpp.mdx
+++ b/docs-en/14-reference/03-connector/cpp.mdx
@@ -114,7 +114,6 @@ This section shows sample code for standard access methods to TDengine clusters
Subscribe and consume
```c
-{{#include examples/c/subscribe.c}}
```
diff --git a/docs-en/20-third-party/01-grafana.mdx b/docs-en/20-third-party/01-grafana.mdx
index b3cab62710..1a84e02c66 100644
--- a/docs-en/20-third-party/01-grafana.mdx
+++ b/docs-en/20-third-party/01-grafana.mdx
@@ -9,7 +9,8 @@ You can learn more about using the TDengine plugin on [GitHub](https://github.co
## Prerequisites
-In order for Grafana to add the TDengine data source successfully, the following preparation is required:
+In order for Grafana to add the TDengine data source successfully, the following preparations are required:
+
1. The TDengine cluster is deployed and functioning properly
2. taosAdapter is installed and running properly. Please refer to the taosAdapter manual for details.
@@ -19,41 +20,34 @@ TDengine currently supports Grafana versions 7.0 and above. Users can go to the
## Configuring Grafana
-You can download The Grafana plugin for TDengine from . The current latest version is 3.1.4.
-
-Recommend using the [``grafana-cli`` command-line tool](https://grafana.com/docs/grafana/latest/administration/cli/) for plugin installation.
+Follow the installation steps in [Grafana](https://grafana.com/grafana/plugins/tdengine-datasource/?tab=installation) with the [``grafana-cli`` command-line tool](https://grafana.com/docs/grafana/latest/administration/cli/) for plugin installation.
```bash
-sudo -u grafana grafana-cli \
- --pluginUrl https://github.com/taosdata/grafanaplugin/releases/download/v3.1.4/tdengine-datasource-3.1.4.zip \
- plugins install tdengine-datasource
+grafana-cli plugins install tdengine-datasource
+# with sudo
+sudo -u grafana grafana-cli plugins install tdengine-datasource
```
-Or download it locally and extract it to the Grafana plugin directory.
+Alternatively, you can manually download the .zip file from [GitHub](https://github.com/taosdata/grafanaplugin/releases/tag/latest) or [Grafana](https://grafana.com/grafana/plugins/tdengine-datasource/?tab=installation) and unpack it into your grafana plugins directory.
```bash
-GF_VERSION=3.1.4
+GF_VERSION=3.2.2
+# from GitHub
wget https://github.com/taosdata/grafanaplugin/releases/download/v$GF_VERSION/tdengine-datasource-$GF_VERSION.zip
+# from Grafana
+wget -O tdengine-datasource-$GF_VERSION.zip https://grafana.com/api/plugins/tdengine-datasource/versions/$GF_VERSION/download
```
-In CentOS 7.2 for example, extract the plugin package to /var/lib/grafana/plugins directory, and restart grafana.
+Take CentOS 7.2 for example, extract the plugin package to /var/lib/grafana/plugins directory, and restart grafana.
```bash
sudo unzip tdengine-datasource-$GF_VERSION.zip -d /var/lib/grafana/plugins/
```
-Grafana versions 7.3+ / 8.x do signature checks on plugins, so you also need to add the following line to the grafana.ini file to use the plugin correctly.
-
-```ini
-[plugins]
-allow_loading_unsigned_plugins = tdengine-datasource
-```
-
-The TDengine plugin can be automatically installed and set up using the following environment variable settings in a Docker environment.
+If Grafana is running in a Docker environment, the TDengine plugin can be automatically installed and set up using the following environment variable settings:
```bash
-GF_INSTALL_PLUGINS=https://github.com/taosdata/grafanaplugin/releases/download/v3.1.4/tdengine-datasource-3.1.4.zip;tdengine- datasource
-GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=tdengine-datasource
+GF_INSTALL_PLUGINS=tdengine-datasource
```
## Using Grafana
diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt
deleted file mode 100644
index 365b1b7172..0000000000
--- a/example/CMakeLists.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-add_executable(tmq "")
-add_executable(tstream "")
-add_executable(demoapi "")
-
-target_sources(tmq
- PRIVATE
- "src/tmq.c"
-)
-
-target_sources(tstream
- PRIVATE
- "src/tstream.c"
-)
-
-target_sources(demoapi
- PRIVATE
- "src/demoapi.c"
-)
-
-target_link_libraries(tmq
- taos_static
-)
-
-target_link_libraries(tstream
- taos_static
-)
-
-target_link_libraries(demoapi
- taos_static
-)
-
-target_include_directories(tmq
- PUBLIC "${TD_SOURCE_DIR}/include/os"
- PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc"
-)
-
-target_include_directories(tstream
- PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc"
-)
-
-target_include_directories(demoapi
- PUBLIC "${TD_SOURCE_DIR}/include/client"
- PUBLIC "${TD_SOURCE_DIR}/include/os"
- PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc"
-)
-
-SET_TARGET_PROPERTIES(tmq PROPERTIES OUTPUT_NAME tmq)
-SET_TARGET_PROPERTIES(tstream PROPERTIES OUTPUT_NAME tstream)
-SET_TARGET_PROPERTIES(demoapi PROPERTIES OUTPUT_NAME demoapi)
diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt
index 17a9257c49..4a9007acec 100644
--- a/examples/c/CMakeLists.txt
+++ b/examples/c/CMakeLists.txt
@@ -3,20 +3,70 @@ PROJECT(TDengine)
IF (TD_LINUX)
INCLUDE_DIRECTORIES(. ${TD_SOURCE_DIR}/src/inc ${TD_SOURCE_DIR}/src/client/inc ${TD_SOURCE_DIR}/inc)
AUX_SOURCE_DIRECTORY(. SRC)
- ADD_EXECUTABLE(demo apitest.c)
- TARGET_LINK_LIBRARIES(demo taos_static trpc tutil pthread )
- ADD_EXECUTABLE(sml schemaless.c)
- TARGET_LINK_LIBRARIES(sml taos_static trpc tutil pthread )
- ADD_EXECUTABLE(subscribe subscribe.c)
- TARGET_LINK_LIBRARIES(subscribe taos_static trpc tutil pthread )
- ADD_EXECUTABLE(epoll epoll.c)
- TARGET_LINK_LIBRARIES(epoll taos_static trpc tutil pthread lua)
+ # ADD_EXECUTABLE(demo apitest.c)
+ #TARGET_LINK_LIBRARIES(demo taos_static trpc tutil pthread )
+ #ADD_EXECUTABLE(sml schemaless.c)
+ #TARGET_LINK_LIBRARIES(sml taos_static trpc tutil pthread )
+ #ADD_EXECUTABLE(subscribe subscribe.c)
+ #TARGET_LINK_LIBRARIES(subscribe taos_static trpc tutil pthread )
+ #ADD_EXECUTABLE(epoll epoll.c)
+ #TARGET_LINK_LIBRARIES(epoll taos_static trpc tutil pthread lua)
+
+ add_executable(tmq "")
+ add_executable(stream_demo "")
+ add_executable(demoapi "")
+
+ target_sources(tmq
+ PRIVATE
+ "tmq.c"
+ )
+
+ target_sources(stream_demo
+ PRIVATE
+ "stream_demo.c"
+ )
+
+ target_sources(demoapi
+ PRIVATE
+ "demoapi.c"
+ )
+
+ target_link_libraries(tmq
+ taos_static
+ )
+
+ target_link_libraries(stream_demo
+ taos_static
+ )
+
+ target_link_libraries(demoapi
+ taos_static
+ )
+
+ target_include_directories(tmq
+ PUBLIC "${TD_SOURCE_DIR}/include/os"
+ PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc"
+ )
+
+ target_include_directories(stream_demo
+ PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc"
+ )
+
+ target_include_directories(demoapi
+ PUBLIC "${TD_SOURCE_DIR}/include/client"
+ PUBLIC "${TD_SOURCE_DIR}/include/os"
+ PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc"
+ )
+
+ SET_TARGET_PROPERTIES(tmq PROPERTIES OUTPUT_NAME tmq)
+ SET_TARGET_PROPERTIES(stream_demo PROPERTIES OUTPUT_NAME stream_demo)
+ SET_TARGET_PROPERTIES(demoapi PROPERTIES OUTPUT_NAME demoapi)
ENDIF ()
IF (TD_DARWIN)
INCLUDE_DIRECTORIES(. ${TD_SOURCE_DIR}/src/inc ${TD_SOURCE_DIR}/src/client/inc ${TD_SOURCE_DIR}/inc)
AUX_SOURCE_DIRECTORY(. SRC)
- ADD_EXECUTABLE(demo demo.c)
- TARGET_LINK_LIBRARIES(demo taos_static trpc tutil pthread lua)
- ADD_EXECUTABLE(epoll epoll.c)
- TARGET_LINK_LIBRARIES(epoll taos_static trpc tutil pthread lua)
+ #ADD_EXECUTABLE(demo demo.c)
+ #TARGET_LINK_LIBRARIES(demo taos_static trpc tutil pthread lua)
+ #ADD_EXECUTABLE(epoll epoll.c)
+ #TARGET_LINK_LIBRARIES(epoll taos_static trpc tutil pthread lua)
ENDIF ()
diff --git a/example/src/demoapi.c b/examples/c/demoapi.c
similarity index 100%
rename from example/src/demoapi.c
rename to examples/c/demoapi.c
diff --git a/example/src/tstream.c b/examples/c/stream_demo.c
similarity index 100%
rename from example/src/tstream.c
rename to examples/c/stream_demo.c
diff --git a/examples/c/subscribe.c b/examples/c/subscribe.c
deleted file mode 100644
index 66d64d295c..0000000000
--- a/examples/c/subscribe.c
+++ /dev/null
@@ -1,263 +0,0 @@
-// sample code for TDengine subscribe/consume API
-// to compile: gcc -o subscribe subscribe.c -ltaos
-
-#include
-#include
-#include
-#include
-#include "../../../include/client/taos.h" // include TDengine header file
-
-int nTotalRows;
-
-void print_result(TAOS_RES* res, int blockFetch) {
- TAOS_ROW row = NULL;
- int num_fields = taos_num_fields(res);
- TAOS_FIELD* fields = taos_fetch_fields(res);
- int nRows = 0;
-
- if (blockFetch) {
- nRows = taos_fetch_block(res, &row);
- //for (int i = 0; i < nRows; i++) {
- // taos_print_row(buf, row + i, fields, num_fields);
- // puts(buf);
- //}
- } else {
- while ((row = taos_fetch_row(res))) {
- char buf[4096] = {0};
- taos_print_row(buf, row, fields, num_fields);
- puts(buf);
- nRows++;
- }
- }
-
- nTotalRows += nRows;
- printf("%d rows consumed.\n", nRows);
-}
-
-
-void subscribe_callback(TAOS_SUB* tsub, TAOS_RES *res, void* param, int code) {
- print_result(res, *(int*)param);
-}
-
-
-void check_row_count(int line, TAOS_RES* res, int expected) {
- int actual = 0;
- TAOS_ROW row;
- while ((row = taos_fetch_row(res))) {
- actual++;
- }
- if (actual != expected) {
- printf("line %d: row count mismatch, expected: %d, actual: %d\n", line, expected, actual);
- } else {
- printf("line %d: %d rows consumed as expected\n", line, actual);
- }
-}
-
-
-void do_query(TAOS* taos, const char* sql) {
- TAOS_RES* res = taos_query(taos, sql);
- taos_free_result(res);
-}
-
-
-void run_test(TAOS* taos) {
- do_query(taos, "drop database if exists test;");
-
- usleep(100000);
- do_query(taos, "create database test;");
- usleep(100000);
- do_query(taos, "use test;");
-
- usleep(100000);
- do_query(taos, "create table meters(ts timestamp, a int) tags(area int);");
-
- do_query(taos, "create table t0 using meters tags(0);");
- do_query(taos, "create table t1 using meters tags(1);");
- do_query(taos, "create table t2 using meters tags(2);");
- do_query(taos, "create table t3 using meters tags(3);");
- do_query(taos, "create table t4 using meters tags(4);");
- do_query(taos, "create table t5 using meters tags(5);");
- do_query(taos, "create table t6 using meters tags(6);");
- do_query(taos, "create table t7 using meters tags(7);");
- do_query(taos, "create table t8 using meters tags(8);");
- do_query(taos, "create table t9 using meters tags(9);");
-
- do_query(taos, "insert into t0 values('2020-01-01 00:00:00.000', 0);");
- do_query(taos, "insert into t0 values('2020-01-01 00:01:00.000', 0);");
- do_query(taos, "insert into t0 values('2020-01-01 00:02:00.000', 0);");
- do_query(taos, "insert into t1 values('2020-01-01 00:00:00.000', 0);");
- do_query(taos, "insert into t1 values('2020-01-01 00:01:00.000', 0);");
- do_query(taos, "insert into t1 values('2020-01-01 00:02:00.000', 0);");
- do_query(taos, "insert into t1 values('2020-01-01 00:03:00.000', 0);");
- do_query(taos, "insert into t2 values('2020-01-01 00:00:00.000', 0);");
- do_query(taos, "insert into t2 values('2020-01-01 00:01:00.000', 0);");
- do_query(taos, "insert into t2 values('2020-01-01 00:01:01.000', 0);");
- do_query(taos, "insert into t2 values('2020-01-01 00:01:02.000', 0);");
- do_query(taos, "insert into t3 values('2020-01-01 00:01:02.000', 0);");
- do_query(taos, "insert into t4 values('2020-01-01 00:01:02.000', 0);");
- do_query(taos, "insert into t5 values('2020-01-01 00:01:02.000', 0);");
- do_query(taos, "insert into t6 values('2020-01-01 00:01:02.000', 0);");
- do_query(taos, "insert into t7 values('2020-01-01 00:01:02.000', 0);");
- do_query(taos, "insert into t8 values('2020-01-01 00:01:02.000', 0);");
- do_query(taos, "insert into t9 values('2020-01-01 00:01:02.000', 0);");
-
- // super tables subscription
- usleep(1000000);
-
- TAOS_SUB* tsub = taos_subscribe(taos, 0, "test", "select * from meters;", NULL, NULL, 0);
- TAOS_RES* res = taos_consume(tsub);
- check_row_count(__LINE__, res, 18);
-
- res = taos_consume(tsub);
- check_row_count(__LINE__, res, 0);
-
- do_query(taos, "insert into t0 values('2020-01-01 00:02:00.001', 0);");
- do_query(taos, "insert into t8 values('2020-01-01 00:01:03.000', 0);");
- res = taos_consume(tsub);
- check_row_count(__LINE__, res, 2);
-
- do_query(taos, "insert into t2 values('2020-01-01 00:01:02.001', 0);");
- do_query(taos, "insert into t1 values('2020-01-01 00:03:00.001', 0);");
- res = taos_consume(tsub);
- check_row_count(__LINE__, res, 2);
-
- do_query(taos, "insert into t1 values('2020-01-01 00:03:00.002', 0);");
- res = taos_consume(tsub);
- check_row_count(__LINE__, res, 1);
-
- // keep progress information and restart subscription
- taos_unsubscribe(tsub, 1);
- do_query(taos, "insert into t0 values('2020-01-01 00:04:00.000', 0);");
- tsub = taos_subscribe(taos, 1, "test", "select * from meters;", NULL, NULL, 0);
- res = taos_consume(tsub);
- check_row_count(__LINE__, res, 24);
-
- // keep progress information and continue previous subscription
- taos_unsubscribe(tsub, 1);
- tsub = taos_subscribe(taos, 0, "test", "select * from meters;", NULL, NULL, 0);
- res = taos_consume(tsub);
- check_row_count(__LINE__, res, 0);
-
- // don't keep progress information and continue previous subscription
- taos_unsubscribe(tsub, 0);
- tsub = taos_subscribe(taos, 0, "test", "select * from meters;", NULL, NULL, 0);
- res = taos_consume(tsub);
- check_row_count(__LINE__, res, 24);
-
- // single meter subscription
-
- taos_unsubscribe(tsub, 0);
- tsub = taos_subscribe(taos, 0, "test", "select * from t0;", NULL, NULL, 0);
- res = taos_consume(tsub);
- check_row_count(__LINE__, res, 5);
-
- res = taos_consume(tsub);
- check_row_count(__LINE__, res, 0);
-
- do_query(taos, "insert into t0 values('2020-01-01 00:04:00.001', 0);");
- res = taos_consume(tsub);
- check_row_count(__LINE__, res, 1);
-
- taos_unsubscribe(tsub, 0);
-}
-
-
-int main(int argc, char *argv[]) {
- const char* host = "127.0.0.1";
- const char* user = "root";
- const char* passwd = "taosdata";
- const char* sql = "select * from meters;";
- const char* topic = "test-multiple";
- int async = 1, restart = 0, keep = 1, test = 0, blockFetch = 0;
-
- for (int i = 1; i < argc; i++) {
- if (strncmp(argv[i], "-h=", 3) == 0) {
- host = argv[i] + 3;
- continue;
- }
- if (strncmp(argv[i], "-u=", 3) == 0) {
- user = argv[i] + 3;
- continue;
- }
- if (strncmp(argv[i], "-p=", 3) == 0) {
- passwd = argv[i] + 3;
- continue;
- }
- if (strcmp(argv[i], "-sync") == 0) {
- async = 0;
- continue;
- }
- if (strcmp(argv[i], "-restart") == 0) {
- restart = 1;
- continue;
- }
- if (strcmp(argv[i], "-single") == 0) {
- sql = "select * from t0;";
- topic = "test-single";
- continue;
- }
- if (strcmp(argv[i], "-nokeep") == 0) {
- keep = 0;
- continue;
- }
- if (strncmp(argv[i], "-sql=", 5) == 0) {
- sql = argv[i] + 5;
- topic = "test-custom";
- continue;
- }
- if (strcmp(argv[i], "-test") == 0) {
- test = 1;
- continue;
- }
- if (strcmp(argv[i], "-block-fetch") == 0) {
- blockFetch = 1;
- continue;
- }
- }
-
- TAOS* taos = taos_connect(host, user, passwd, "", 0);
- if (taos == NULL) {
- printf("failed to connect to db, reason:%s\n", taos_errstr(taos));
- exit(1);
- }
-
- if (test) {
- run_test(taos);
- taos_close(taos);
- exit(0);
- }
-
- taos_select_db(taos, "test");
- TAOS_SUB* tsub = NULL;
- if (async) {
- // create an asynchronized subscription, the callback function will be called every 1s
- tsub = taos_subscribe(taos, restart, topic, sql, subscribe_callback, &blockFetch, 1000);
- } else {
- // create an synchronized subscription, need to call 'taos_consume' manually
- tsub = taos_subscribe(taos, restart, topic, sql, NULL, NULL, 0);
- }
-
- if (tsub == NULL) {
- printf("failed to create subscription.\n");
- exit(0);
- }
-
- if (async) {
- getchar();
- } else while(1) {
- TAOS_RES* res = taos_consume(tsub);
- if (res == NULL) {
- printf("failed to consume data.");
- break;
- } else {
- print_result(res, blockFetch);
- getchar();
- }
- }
-
- printf("total rows consumed: %d\n", nTotalRows);
- taos_unsubscribe(tsub, keep);
- taos_close(taos);
-
- return 0;
-}
diff --git a/example/src/tmq.c b/examples/c/tmq.c
similarity index 97%
rename from example/src/tmq.c
rename to examples/c/tmq.c
index 5eecb5e4cc..2e8aa21da7 100644
--- a/example/src/tmq.c
+++ b/examples/c/tmq.c
@@ -24,6 +24,7 @@ static void msg_process(TAOS_RES* msg) {
char buf[1024];
/*memset(buf, 0, 1024);*/
printf("topic: %s\n", tmq_get_topic_name(msg));
+ printf("db: %s\n", tmq_get_db_name(msg));
printf("vg: %d\n", tmq_get_vgroup_id(msg));
while (1) {
TAOS_ROW row = taos_fetch_row(msg);
@@ -165,7 +166,6 @@ tmq_t* build_consumer() {
tmq_conf_set(conf, "group.id", "tg2");
tmq_conf_set(conf, "td.connect.user", "root");
tmq_conf_set(conf, "td.connect.pass", "taosdata");
- /*tmq_conf_set(conf, "td.connect.db", "abc1");*/
tmq_conf_set(conf, "msg.with.table.name", "true");
tmq_conf_set(conf, "enable.auto.commit", "false");
tmq_conf_set_auto_commit_cb(conf, tmq_commit_cb_print, NULL);
@@ -191,21 +191,18 @@ void basic_consume_loop(tmq_t* tmq, tmq_list_t* topics) {
return;
}
int32_t cnt = 0;
- /*clock_t startTime = clock();*/
while (running) {
TAOS_RES* tmqmessage = tmq_consumer_poll(tmq, 0);
if (tmqmessage) {
cnt++;
msg_process(tmqmessage);
- if (cnt >= 2) break;
+ /*if (cnt >= 2) break;*/
/*printf("get data\n");*/
taos_free_result(tmqmessage);
/*} else {*/
/*break;*/
}
}
- /*clock_t endTime = clock();*/
- /*printf("log cnt: %d %f s\n", cnt, (double)(endTime - startTime) / CLOCKS_PER_SEC);*/
err = tmq_consumer_close(tmq);
if (err)
diff --git a/include/client/taos.h b/include/client/taos.h
index bab0c18db1..b65091f52b 100644
--- a/include/client/taos.h
+++ b/include/client/taos.h
@@ -144,8 +144,8 @@ DLL_EXPORT int taos_stmt_set_tbname_tags(TAOS_STMT *stmt, const char *nam
DLL_EXPORT int taos_stmt_set_tbname(TAOS_STMT *stmt, const char *name);
DLL_EXPORT int taos_stmt_set_tags(TAOS_STMT *stmt, TAOS_MULTI_BIND *tags);
DLL_EXPORT int taos_stmt_set_sub_tbname(TAOS_STMT *stmt, const char *name);
-DLL_EXPORT int taos_stmt_get_tag_fields(TAOS_STMT *stmt, int* fieldNum, TAOS_FIELD_E** fields);
-DLL_EXPORT int taos_stmt_get_col_fields(TAOS_STMT *stmt, int* fieldNum, TAOS_FIELD_E** fields);
+DLL_EXPORT int taos_stmt_get_tag_fields(TAOS_STMT *stmt, int *fieldNum, TAOS_FIELD_E **fields);
+DLL_EXPORT int taos_stmt_get_col_fields(TAOS_STMT *stmt, int *fieldNum, TAOS_FIELD_E **fields);
DLL_EXPORT int taos_stmt_is_insert(TAOS_STMT *stmt, int *insert);
DLL_EXPORT int taos_stmt_num_params(TAOS_STMT *stmt, int *nums);
@@ -269,6 +269,7 @@ DLL_EXPORT void tmq_conf_set_auto_commit_cb(tmq_conf_t *conf, tmq_comm
/* -------------------------TMQ MSG HANDLE INTERFACE---------------------- */
DLL_EXPORT const char *tmq_get_topic_name(TAOS_RES *res);
+DLL_EXPORT const char *tmq_get_db_name(TAOS_RES *res);
DLL_EXPORT int32_t tmq_get_vgroup_id(TAOS_RES *res);
DLL_EXPORT const char *tmq_get_table_name(TAOS_RES *res);
diff --git a/include/common/taosdef.h b/include/common/taosdef.h
index d39c7a1215..516df71b0b 100644
--- a/include/common/taosdef.h
+++ b/include/common/taosdef.h
@@ -97,6 +97,7 @@ extern char *qtypeStr[];
#undef TD_DEBUG_PRINT_ROW
#undef TD_DEBUG_PRINT_TSDB_LOAD_DCOLS
+#undef TD_DEBUG_PRINT_TAG
#ifdef __cplusplus
}
diff --git a/include/common/tdataformat.h b/include/common/tdataformat.h
index ef931ed3b1..10bc6a6176 100644
--- a/include/common/tdataformat.h
+++ b/include/common/tdataformat.h
@@ -18,6 +18,7 @@
#include "os.h"
#include "talgo.h"
+#include "tarray.h"
#include "tencode.h"
#include "ttypes.h"
#include "tutil.h"
@@ -29,6 +30,7 @@ extern "C" {
typedef struct SSchema SSchema;
typedef struct STColumn STColumn;
typedef struct STSchema STSchema;
+typedef struct SValue SValue;
typedef struct SColVal SColVal;
typedef struct STSRow2 STSRow2;
typedef struct STSRowBuilder STSRowBuilder;
@@ -39,32 +41,37 @@ typedef struct STag STag;
int32_t tTSchemaCreate(int32_t sver, SSchema *pSchema, int32_t nCols, STSchema **ppTSchema);
void tTSchemaDestroy(STSchema *pTSchema);
-// SColVal
-#define ColValNONE ((SColVal){.type = COL_VAL_NONE, .nData = 0, .pData = NULL})
-#define ColValNULL ((SColVal){.type = COL_VAL_NULL, .nData = 0, .pData = NULL})
-#define ColValDATA(nData, pData) ((SColVal){.type = COL_VAL_DATA, .nData = (nData), .pData = (pData)})
-
// STSRow2
+#define COL_VAL_NONE(CID) ((SColVal){.cid = (CID), .isNone = 1})
+#define COL_VAL_NULL(CID) ((SColVal){.cid = (CID), .isNull = 1})
+#define COL_VAL_VALUE(CID, V) ((SColVal){.cid = (CID), .value = (V)})
+
+int32_t tTSRowClone(const STSRow2 *pRow, STSRow2 **ppRow);
+void tTSRowFree(STSRow2 *pRow);
+void tTSRowGet(STSRow2 *pRow, STSchema *pTSchema, int32_t iCol, SColVal *pColVal);
+int32_t tTSRowToArray(STSRow2 *pRow, STSchema *pTSchema, SArray **ppArray);
int32_t tPutTSRow(uint8_t *p, STSRow2 *pRow);
int32_t tGetTSRow(uint8_t *p, STSRow2 *pRow);
-int32_t tTSRowDup(const STSRow2 *pRow, STSRow2 **ppRow);
-void tTSRowFree(STSRow2 *pRow);
-int32_t tTSRowGet(const STSRow2 *pRow, STSchema *pTSchema, int32_t iCol, SColVal *pColVal);
// STSRowBuilder
+#if 0
int32_t tTSRowBuilderInit(STSRowBuilder *pBuilder, int32_t sver, int32_t nCols, SSchema *pSchema);
void tTSRowBuilderClear(STSRowBuilder *pBuilder);
void tTSRowBuilderReset(STSRowBuilder *pBuilder);
int32_t tTSRowBuilderPut(STSRowBuilder *pBuilder, int32_t cid, uint8_t *pData, uint32_t nData);
int32_t tTSRowBuilderGetRow(STSRowBuilder *pBuilder, const STSRow2 **ppRow);
+#endif
// STag
-int32_t tTagNew(STagVal *pTagVals, int16_t nTag, STag **ppTag);
+int32_t tTagNew(SArray *pArray, int32_t version, int8_t isJson, STag **ppTag);
void tTagFree(STag *pTag);
-int32_t tTagSet(STag *pTag, SSchema *pSchema, int32_t nCols, int iCol, uint8_t *pData, uint32_t nData, STag **ppTag);
-void tTagGet(STag *pTag, int16_t cid, int8_t type, uint8_t **ppData, uint32_t *nData);
+bool tTagGet(const STag *pTag, STagVal *pTagVal);
+char* tTagValToData(const STagVal *pTagVal, bool isJson);
int32_t tEncodeTag(SEncoder *pEncoder, const STag *pTag);
int32_t tDecodeTag(SDecoder *pDecoder, STag **ppTag);
+int32_t tTagToValArray(const STag *pTag, SArray **ppArray);
+void debugPrintSTag(STag *pTag, const char *tag, int32_t ln); // TODO: remove
+void debugCheckTags(STag *pTag); // TODO: remove
// STRUCT =================
struct STColumn {
@@ -87,7 +94,9 @@ struct STSchema {
#define TSROW_HAS_NONE ((uint8_t)0x1)
#define TSROW_HAS_NULL ((uint8_t)0x2U)
#define TSROW_HAS_VAL ((uint8_t)0x4U)
-#define TSROW_KV_ROW ((uint8_t)0x10U)
+#define TSROW_KV_SMALL ((uint8_t)0x10U)
+#define TSROW_KV_MID ((uint8_t)0x20U)
+#define TSROW_KV_BIG ((uint8_t)0x40U)
struct STSRow2 {
TSKEY ts;
uint8_t flags;
@@ -110,20 +119,60 @@ struct STSRowBuilder {
STSRow2 row;
};
-typedef enum { COL_VAL_NONE = 0, COL_VAL_NULL = 1, COL_VAL_DATA = 2 } EColValT;
-struct SColVal {
- EColValT type;
- uint32_t nData;
- uint8_t *pData;
+struct SValue {
+ union {
+ int8_t i8; // TSDB_DATA_TYPE_BOOL||TSDB_DATA_TYPE_TINYINT
+ uint8_t u8; // TSDB_DATA_TYPE_UTINYINT
+ int16_t i16; // TSDB_DATA_TYPE_SMALLINT
+ uint16_t u16; // TSDB_DATA_TYPE_USMALLINT
+ int32_t i32; // TSDB_DATA_TYPE_INT
+ uint32_t u32; // TSDB_DATA_TYPE_UINT
+ int64_t i64; // TSDB_DATA_TYPE_BIGINT
+ uint64_t u64; // TSDB_DATA_TYPE_UBIGINT
+ TSKEY ts; // TSDB_DATA_TYPE_TIMESTAMP
+ float f; // TSDB_DATA_TYPE_FLOAT
+ double d; // TSDB_DATA_TYPE_DOUBLE
+ struct {
+ uint32_t nData;
+ uint8_t *pData;
+ };
+ };
};
-struct STagVal {
- int16_t cid;
- int8_t type;
- uint32_t nData;
- uint8_t *pData;
+struct SColVal {
+ int16_t cid;
+ int8_t isNone;
+ int8_t isNull;
+ SValue value;
};
+#pragma pack(push, 1)
+struct STagVal {
+ union {
+ int16_t cid;
+ char *pKey;
+ };
+ int8_t type;
+ union {
+ int64_t i64;
+ struct {
+ uint32_t nData;
+ uint8_t *pData;
+ };
+ };
+};
+
+#define TD_TAG_JSON ((int8_t)0x40) // distinguish JSON string and JSON value with the highest bit
+#define TD_TAG_LARGE ((int8_t)0x20)
+struct STag {
+ int8_t flags;
+ int16_t len;
+ int16_t nTag;
+ int32_t ver;
+ int8_t idx[];
+};
+#pragma pack(pop)
+
#if 1 //================================================================================================================================================
// Imported since 3.0 and use bitmap to demonstrate None/Null/Norm, while use Null/Norm below 3.0 without of bitmap.
#define TD_SUPPORT_BITMAP
@@ -366,109 +415,6 @@ SDataCols *tdFreeDataCols(SDataCols *pCols);
int32_t tdMergeDataCols(SDataCols *target, SDataCols *source, int32_t rowsToMerge, int32_t *pOffset, bool update,
TDRowVerT maxVer);
-// ----------------- K-V data row structure
-/* |<-------------------------------------- len -------------------------------------------->|
- * |<----- header ----->|<--------------------------- body -------------------------------->|
- * +----------+----------+---------------------------------+---------------------------------+
- * | uint16_t | int16_t | | |
- * +----------+----------+---------------------------------+---------------------------------+
- * | len | ncols | cols index | data part |
- * +----------+----------+---------------------------------+---------------------------------+
- */
-typedef void *SKVRow;
-
-typedef struct {
- int16_t colId;
- uint16_t offset;
-} SColIdx;
-
-#define TD_KV_ROW_HEAD_SIZE (sizeof(uint16_t) + sizeof(int16_t))
-
-#define kvRowLen(r) (*(uint16_t *)(r))
-#define kvRowNCols(r) (*(int16_t *)POINTER_SHIFT(r, sizeof(uint16_t)))
-#define kvRowSetLen(r, len) kvRowLen(r) = (len)
-#define kvRowSetNCols(r, n) kvRowNCols(r) = (n)
-#define kvRowColIdx(r) (SColIdx *)POINTER_SHIFT(r, TD_KV_ROW_HEAD_SIZE)
-#define kvRowValues(r) POINTER_SHIFT(r, TD_KV_ROW_HEAD_SIZE + sizeof(SColIdx) * kvRowNCols(r))
-#define kvRowCpy(dst, r) memcpy((dst), (r), kvRowLen(r))
-#define kvRowColVal(r, colIdx) POINTER_SHIFT(kvRowValues(r), (colIdx)->offset)
-#define kvRowColIdxAt(r, i) (kvRowColIdx(r) + (i))
-#define kvRowFree(r) taosMemoryFreeClear(r)
-#define kvRowEnd(r) POINTER_SHIFT(r, kvRowLen(r))
-#define kvRowValLen(r) (kvRowLen(r) - TD_KV_ROW_HEAD_SIZE - sizeof(SColIdx) * kvRowNCols(r))
-#define kvRowTKey(r) (*(TKEY *)(kvRowValues(r)))
-#define kvRowKey(r) tdGetKey(kvRowTKey(r))
-#define kvRowKeys(r) POINTER_SHIFT(r, *(uint16_t *)POINTER_SHIFT(r, TD_KV_ROW_HEAD_SIZE + sizeof(int16_t)))
-#define kvRowDeleted(r) TKEY_IS_DELETED(kvRowTKey(r))
-
-SKVRow tdKVRowDup(SKVRow row);
-int32_t tdSetKVRowDataOfCol(SKVRow *orow, int16_t colId, int8_t type, void *value);
-int32_t tdEncodeKVRow(void **buf, SKVRow row);
-void *tdDecodeKVRow(void *buf, SKVRow *row);
-void tdSortKVRowByColIdx(SKVRow row);
-
-static FORCE_INLINE int32_t comparTagId(const void *key1, const void *key2) {
- if (*(int16_t *)key1 > ((SColIdx *)key2)->colId) {
- return 1;
- } else if (*(int16_t *)key1 < ((SColIdx *)key2)->colId) {
- return -1;
- } else {
- return 0;
- }
-}
-
-static FORCE_INLINE void *tdGetKVRowValOfCol(const SKVRow row, int16_t colId) {
- void *ret = taosbsearch(&colId, kvRowColIdx(row), kvRowNCols(row), sizeof(SColIdx), comparTagId, TD_EQ);
- if (ret == NULL) return NULL;
- return kvRowColVal(row, (SColIdx *)ret);
-}
-
-static FORCE_INLINE void *tdGetKVRowIdxOfCol(SKVRow row, int16_t colId) {
- return taosbsearch(&colId, kvRowColIdx(row), kvRowNCols(row), sizeof(SColIdx), comparTagId, TD_EQ);
-}
-
-// ----------------- K-V data row builder
-typedef struct {
- int16_t tCols;
- int16_t nCols;
- SColIdx *pColIdx;
- uint16_t alloc;
- uint16_t size;
- void *buf;
-} SKVRowBuilder;
-
-int32_t tdInitKVRowBuilder(SKVRowBuilder *pBuilder);
-void tdDestroyKVRowBuilder(SKVRowBuilder *pBuilder);
-void tdResetKVRowBuilder(SKVRowBuilder *pBuilder);
-SKVRow tdGetKVRowFromBuilder(SKVRowBuilder *pBuilder);
-
-static FORCE_INLINE int32_t tdAddColToKVRow(SKVRowBuilder *pBuilder, col_id_t colId, const void *value, int32_t tlen) {
- if (pBuilder->nCols >= pBuilder->tCols) {
- pBuilder->tCols *= 2;
- SColIdx *pColIdx = (SColIdx *)taosMemoryRealloc((void *)(pBuilder->pColIdx), sizeof(SColIdx) * pBuilder->tCols);
- if (pColIdx == NULL) return -1;
- pBuilder->pColIdx = pColIdx;
- }
-
- pBuilder->pColIdx[pBuilder->nCols].colId = colId;
- pBuilder->pColIdx[pBuilder->nCols].offset = pBuilder->size;
-
- pBuilder->nCols++;
-
- if (tlen > pBuilder->alloc - pBuilder->size) {
- while (tlen > pBuilder->alloc - pBuilder->size) {
- pBuilder->alloc *= 2;
- }
- void *buf = taosMemoryRealloc(pBuilder->buf, pBuilder->alloc);
- if (buf == NULL) return -1;
- pBuilder->buf = buf;
- }
-
- memcpy(POINTER_SHIFT(pBuilder->buf, pBuilder->size), value, tlen);
- pBuilder->size += tlen;
-
- return 0;
-}
#endif
#ifdef __cplusplus
@@ -476,3 +422,4 @@ static FORCE_INLINE int32_t tdAddColToKVRow(SKVRowBuilder *pBuilder, col_id_t co
#endif
#endif /*_TD_COMMON_DATA_FORMAT_H_*/
+
diff --git a/include/common/tmsg.h b/include/common/tmsg.h
index ac65e3da8b..d33f668365 100644
--- a/include/common/tmsg.h
+++ b/include/common/tmsg.h
@@ -244,7 +244,7 @@ typedef struct {
const void* pMsg;
} SSubmitMsgIter;
-int32_t tInitSubmitMsgIter(SSubmitReq* pMsg, SSubmitMsgIter* pIter);
+int32_t tInitSubmitMsgIter(const SSubmitReq* pMsg, SSubmitMsgIter* pIter);
int32_t tGetSubmitMsgNext(SSubmitMsgIter* pIter, SSubmitBlk** pPBlock);
int32_t tInitSubmitBlkIter(SSubmitMsgIter* pMsgIter, SSubmitBlk* pBlock, SSubmitBlkIter* pIter);
STSRow* tGetSubmitBlkNext(SSubmitBlkIter* pIter);
@@ -287,7 +287,7 @@ typedef struct SSchema {
char name[TSDB_COL_NAME_LEN];
} SSchema;
-#define COL_IS_SET(FLG) ((FLG) & (COL_SET_VAL | COL_SET_NULL) != 0)
+#define COL_IS_SET(FLG) (((FLG) & (COL_SET_VAL | COL_SET_NULL)) != 0)
#define COL_CLR_SET(FLG) ((FLG) &= (~(COL_SET_VAL | COL_SET_NULL)))
#define IS_BSMA_ON(s) (((s)->flags & 0x01) == COL_SMA_ON)
@@ -945,7 +945,6 @@ typedef struct {
int64_t timeInFetchQueue;
} SQnodeLoad;
-
typedef struct {
int32_t sver; // software version
int64_t dnodeVer; // dnode table version in sdb
@@ -1002,7 +1001,6 @@ typedef struct {
typedef struct {
int32_t vgId;
- int32_t dnodeId;
char db[TSDB_DB_FNAME_LEN];
int64_t dbUid;
int32_t vgVersion;
@@ -1025,16 +1023,14 @@ typedef struct {
int8_t compression;
int8_t strict;
int8_t cacheLastRow;
+ int8_t isTsma;
+ int8_t standby;
int8_t replica;
int8_t selfIndex;
SReplica replicas[TSDB_MAX_REPLICA];
int32_t numOfRetensions;
SArray* pRetensions; // SRetention
-
- // for tsma
- int8_t isTsma;
- void* pTsma;
-
+ void* pTsma;
} SCreateVnodeReq;
int32_t tSerializeSCreateVnodeReq(void* buf, int32_t bufLen, SCreateVnodeReq* pReq);
@@ -1072,8 +1068,8 @@ typedef struct {
int8_t walLevel;
int8_t strict;
int8_t cacheLastRow;
- int8_t replica;
int8_t selfIndex;
+ int8_t replica;
SReplica replicas[TSDB_MAX_REPLICA];
} SAlterVnodeReq;
@@ -1786,6 +1782,15 @@ typedef struct SVCreateTbReq {
int tEncodeSVCreateTbReq(SEncoder* pCoder, const SVCreateTbReq* pReq);
int tDecodeSVCreateTbReq(SDecoder* pCoder, SVCreateTbReq* pReq);
+static FORCE_INLINE void tdDestroySVCreateTbReq(SVCreateTbReq* req) {
+ taosMemoryFreeClear(req->name);
+ if (req->type == TSDB_CHILD_TABLE) {
+ taosMemoryFreeClear(req->ctb.pTag);
+ } else if (req->type == TSDB_NORMAL_TABLE) {
+ taosMemoryFreeClear(req->ntb.schemaRow.pSchema);
+ }
+}
+
typedef struct {
int32_t nReqs;
union {
@@ -1977,7 +1982,7 @@ typedef struct {
int8_t killConnection;
int8_t align[3];
SEpSet epSet;
- SArray *pQnodeList;
+ SArray* pQnodeList;
} SQueryHbRspBasic;
typedef struct {
@@ -2207,10 +2212,8 @@ typedef struct {
int64_t newConsumerId;
char subKey[TSDB_SUBSCRIBE_KEY_LEN];
int8_t subType;
- // int8_t withTbName;
- // int8_t withSchema;
- // int8_t withTag;
- char* qmsg;
+ char* qmsg;
+ int64_t suid;
} SMqRebVgReq;
static FORCE_INLINE int32_t tEncodeSMqRebVgReq(void** buf, const SMqRebVgReq* pReq) {
@@ -2221,11 +2224,10 @@ static FORCE_INLINE int32_t tEncodeSMqRebVgReq(void** buf, const SMqRebVgReq* pR
tlen += taosEncodeFixedI64(buf, pReq->newConsumerId);
tlen += taosEncodeString(buf, pReq->subKey);
tlen += taosEncodeFixedI8(buf, pReq->subType);
- // tlen += taosEncodeFixedI8(buf, pReq->withTbName);
- // tlen += taosEncodeFixedI8(buf, pReq->withSchema);
- // tlen += taosEncodeFixedI8(buf, pReq->withTag);
if (pReq->subType == TOPIC_SUB_TYPE__COLUMN) {
tlen += taosEncodeString(buf, pReq->qmsg);
+ } else if (pReq->subType == TOPIC_SUB_TYPE__TABLE) {
+ tlen += taosEncodeFixedI64(buf, pReq->suid);
}
return tlen;
}
@@ -2237,11 +2239,10 @@ static FORCE_INLINE void* tDecodeSMqRebVgReq(const void* buf, SMqRebVgReq* pReq)
buf = taosDecodeFixedI64(buf, &pReq->newConsumerId);
buf = taosDecodeStringTo(buf, pReq->subKey);
buf = taosDecodeFixedI8(buf, &pReq->subType);
- // buf = taosDecodeFixedI8(buf, &pReq->withTbName);
- // buf = taosDecodeFixedI8(buf, &pReq->withSchema);
- // buf = taosDecodeFixedI8(buf, &pReq->withTag);
if (pReq->subType == TOPIC_SUB_TYPE__COLUMN) {
buf = taosDecodeString(buf, &pReq->qmsg);
+ } else if (pReq->subType == TOPIC_SUB_TYPE__TABLE) {
+ buf = taosDecodeFixedI64(buf, &pReq->suid);
}
return (void*)buf;
}
@@ -2305,6 +2306,7 @@ typedef struct {
int8_t intervalUnit; // MACRO: TIME_UNIT_XXX
int8_t slidingUnit; // MACRO: TIME_UNIT_XXX
int8_t timezoneInt; // sma data expired if timezone changes.
+ int32_t dstVgId;
char indexName[TSDB_INDEX_NAME_LEN];
int32_t exprLen;
int32_t tagsFilterLen;
@@ -2474,7 +2476,7 @@ static FORCE_INLINE void* tDecodeSMqSubVgEp(void* buf, SMqSubVgEp* pVgEp) {
typedef struct {
char topic[TSDB_TOPIC_FNAME_LEN];
- int8_t isSchemaAdaptive;
+ char db[TSDB_DB_FNAME_LEN];
SArray* vgs; // SArray
SSchemaWrapper schema;
} SMqSubTopicEp;
@@ -2482,7 +2484,7 @@ typedef struct {
static FORCE_INLINE int32_t tEncodeSMqSubTopicEp(void** buf, const SMqSubTopicEp* pTopicEp) {
int32_t tlen = 0;
tlen += taosEncodeString(buf, pTopicEp->topic);
- tlen += taosEncodeFixedI8(buf, pTopicEp->isSchemaAdaptive);
+ tlen += taosEncodeString(buf, pTopicEp->db);
int32_t sz = taosArrayGetSize(pTopicEp->vgs);
tlen += taosEncodeFixedI32(buf, sz);
for (int32_t i = 0; i < sz; i++) {
@@ -2495,7 +2497,7 @@ static FORCE_INLINE int32_t tEncodeSMqSubTopicEp(void** buf, const SMqSubTopicEp
static FORCE_INLINE void* tDecodeSMqSubTopicEp(void* buf, SMqSubTopicEp* pTopicEp) {
buf = taosDecodeStringTo(buf, pTopicEp->topic);
- buf = taosDecodeFixedI8(buf, &pTopicEp->isSchemaAdaptive);
+ buf = taosDecodeStringTo(buf, pTopicEp->db);
int32_t sz;
buf = taosDecodeFixedI32(buf, &sz);
pTopicEp->vgs = taosArrayInit(sz, sizeof(SMqSubVgEp));
@@ -2573,6 +2575,12 @@ static FORCE_INLINE void* tDecodeSMqDataBlkRsp(const void* buf, SMqDataBlkRsp* p
buf = taosDecodeFixedI8(buf, &pRsp->withTbName);
buf = taosDecodeFixedI8(buf, &pRsp->withSchema);
buf = taosDecodeFixedI8(buf, &pRsp->withTag);
+ if (pRsp->withTbName) {
+ pRsp->blockTbName = taosArrayInit(pRsp->blockNum, sizeof(void*));
+ }
+ if (pRsp->withSchema) {
+ pRsp->blockSchema = taosArrayInit(pRsp->blockNum, sizeof(void*));
+ }
for (int32_t i = 0; i < pRsp->blockNum; i++) {
int32_t bLen = 0;
@@ -2582,20 +2590,14 @@ static FORCE_INLINE void* tDecodeSMqDataBlkRsp(const void* buf, SMqDataBlkRsp* p
taosArrayPush(pRsp->blockDataLen, &bLen);
taosArrayPush(pRsp->blockData, &data);
if (pRsp->withSchema) {
- pRsp->blockSchema = taosArrayInit(pRsp->blockNum, sizeof(void*));
SSchemaWrapper* pSW = (SSchemaWrapper*)taosMemoryMalloc(sizeof(SSchemaWrapper));
buf = taosDecodeSSchemaWrapper(buf, pSW);
taosArrayPush(pRsp->blockSchema, &pSW);
- } else {
- pRsp->blockSchema = NULL;
}
if (pRsp->withTbName) {
- pRsp->blockTbName = taosArrayInit(pRsp->blockNum, sizeof(void*));
char* name = NULL;
buf = taosDecodeString(buf, &name);
taosArrayPush(pRsp->blockTbName, &name);
- } else {
- pRsp->blockTbName = NULL;
}
}
}
@@ -2662,6 +2664,23 @@ typedef struct {
int32_t tEncodeSVSubmitReq(SEncoder* pCoder, const SVSubmitReq* pReq);
int32_t tDecodeSVSubmitReq(SDecoder* pCoder, SVSubmitReq* pReq);
+// TDMT_VND_DELETE
+typedef struct {
+ TSKEY sKey;
+ TSKEY eKey;
+
+ // super table
+ char* stbName;
+
+ // child/normal
+ char* tbName;
+} SVDeleteReq;
+
+typedef struct {
+ int32_t code;
+ // TODO
+} SVDeleteRsp;
+
#pragma pack(pop)
#ifdef __cplusplus
diff --git a/include/common/tmsgdef.h b/include/common/tmsgdef.h
index d7db2399e8..ba4a221a9f 100644
--- a/include/common/tmsgdef.h
+++ b/include/common/tmsgdef.h
@@ -221,9 +221,11 @@ enum {
TD_DEF_MSG_TYPE(TDMT_VND_SYNC_APPLY_MSG, "vnode-sync-apply-msg", NULL, NULL)
TD_DEF_MSG_TYPE(TDMT_VND_SYNC_CONFIG_CHANGE, "vnode-sync-config-change", NULL, NULL)
- TD_DEF_MSG_TYPE(TDMT_VND_SYNC_VNODE, "vnode-sync-vnode", NULL, NULL)
- TD_DEF_MSG_TYPE(TDMT_VND_ALTER_VNODE, "vnode-alter-vnode", NULL, NULL)
- TD_DEF_MSG_TYPE(TDMT_VND_COMPACT_VNODE, "vnode-compact-vnode", NULL, NULL)
+ TD_DEF_MSG_TYPE(TDMT_VND_ALTER_CONFIG, "vnode-alter-config", NULL, NULL)
+ TD_DEF_MSG_TYPE(TDMT_VND_ALTER_REPLICA, "vnode-alter-replica", NULL, NULL)
+ TD_DEF_MSG_TYPE(TDMT_VND_COMPACT, "vnode-compact", NULL, NULL)
+
+ TD_DEF_MSG_TYPE(TDMT_VND_DELETE, "vnode-delete-data", SVDeleteReq, SVDeleteRsp)
// Requests handled by QNODE
TD_NEW_MSG_SEG(TDMT_QND_MSG)
diff --git a/include/libs/function/functionMgt.h b/include/libs/function/functionMgt.h
index 922136b590..f3e28936af 100644
--- a/include/libs/function/functionMgt.h
+++ b/include/libs/function/functionMgt.h
@@ -156,6 +156,9 @@ bool fmIsDynamicScanOptimizedFunc(int32_t funcId);
bool fmIsMultiResFunc(int32_t funcId);
bool fmIsRepeatScanFunc(int32_t funcId);
bool fmIsUserDefinedFunc(int32_t funcId);
+bool fmIsDistExecFunc(int32_t funcId);
+
+int32_t fmGetDistMethod(const SFunctionNode* pFunc, SFunctionNode** pPartialFunc, SFunctionNode** pMergeFunc);
typedef enum EFuncDataRequired {
FUNC_DATA_REQUIRED_DATA_LOAD = 1,
diff --git a/include/libs/nodes/nodes.h b/include/libs/nodes/nodes.h
index d960ccbd65..41c196c916 100644
--- a/include/libs/nodes/nodes.h
+++ b/include/libs/nodes/nodes.h
@@ -189,6 +189,7 @@ typedef enum ENodeType {
QUERY_NODE_LOGIC_PLAN_PROJECT,
QUERY_NODE_LOGIC_PLAN_VNODE_MODIF,
QUERY_NODE_LOGIC_PLAN_EXCHANGE,
+ QUERY_NODE_LOGIC_PLAN_MERGE,
QUERY_NODE_LOGIC_PLAN_WINDOW,
QUERY_NODE_LOGIC_PLAN_FILL,
QUERY_NODE_LOGIC_PLAN_SORT,
@@ -206,6 +207,7 @@ typedef enum ENodeType {
QUERY_NODE_PHYSICAL_PLAN_JOIN,
QUERY_NODE_PHYSICAL_PLAN_AGG,
QUERY_NODE_PHYSICAL_PLAN_EXCHANGE,
+ QUERY_NODE_PHYSICAL_PLAN_MERGE,
QUERY_NODE_PHYSICAL_PLAN_SORT,
QUERY_NODE_PHYSICAL_PLAN_INTERVAL,
QUERY_NODE_PHYSICAL_PLAN_STREAM_INTERVAL,
diff --git a/include/libs/nodes/plannodes.h b/include/libs/nodes/plannodes.h
index 44e7295b69..5892bffac2 100644
--- a/include/libs/nodes/plannodes.h
+++ b/include/libs/nodes/plannodes.h
@@ -95,9 +95,15 @@ typedef struct SVnodeModifLogicNode {
typedef struct SExchangeLogicNode {
SLogicNode node;
int32_t srcGroupId;
- uint8_t precision;
} SExchangeLogicNode;
+typedef struct SMergeLogicNode {
+ SLogicNode node;
+ SNodeList* pMergeKeys;
+ int32_t numOfChannels;
+ int32_t srcGroupId;
+} SMergeLogicNode;
+
typedef enum EWindowType { WINDOW_TYPE_INTERVAL = 1, WINDOW_TYPE_SESSION, WINDOW_TYPE_STATE } EWindowType;
typedef struct SWindowLogicNode {
@@ -268,6 +274,13 @@ typedef struct SExchangePhysiNode {
SNodeList* pSrcEndPoints; // element is SDownstreamSource, scheduler fill by calling qSetSuplanExecutionNode
} SExchangePhysiNode;
+typedef struct SMergePhysiNode {
+ SPhysiNode node;
+ SNodeList* pMergeKeys;
+ int32_t numOfChannels;
+ int32_t srcGroupId;
+} SMergePhysiNode;
+
typedef struct SWinodwPhysiNode {
SPhysiNode node;
SNodeList* pExprs; // these are expression list of parameter expression of function
diff --git a/include/libs/stream/tstream.h b/include/libs/stream/tstream.h
index 8aaf9a79dc..f7ad7b4ed8 100644
--- a/include/libs/stream/tstream.h
+++ b/include/libs/stream/tstream.h
@@ -61,11 +61,8 @@ enum {
};
typedef struct {
- int8_t type;
-
- int32_t sourceVg;
- int64_t sourceVer;
-
+ int8_t type;
+ int64_t ver;
int32_t* dataRef;
SSubmitReq* data;
} SStreamDataSubmit;
@@ -83,6 +80,37 @@ typedef struct {
int8_t type;
} SStreamCheckpoint;
+typedef struct {
+ STaosQueue* queue;
+ STaosQall* qall;
+ void* qItem;
+ int8_t failed;
+} SStreamQ;
+
+static FORCE_INLINE void* streamQCurItem(SStreamQ* queue) {
+ //
+ return queue->qItem;
+}
+
+static FORCE_INLINE void* streamQNextItem(SStreamQ* queue) {
+ int8_t failed = atomic_load_8(&queue->failed);
+ if (failed) {
+ ASSERT(queue->qItem != NULL);
+ return streamQCurItem(queue);
+ } else {
+ taosGetQitem(queue->qall, &queue->qItem);
+ if (queue->qItem == NULL) {
+ taosReadAllQitems(queue->queue, queue->qall);
+ taosGetQitem(queue->qall, &queue->qItem);
+ }
+ return streamQCurItem(queue);
+ }
+}
+
+static FORCE_INLINE void streamQSetFail(SStreamQ* queue) { atomic_store_8(&queue->failed, 1); }
+
+static FORCE_INLINE void streamQSetSuccess(SStreamQ* queue) { atomic_store_8(&queue->failed, 0); }
+
static FORCE_INLINE SStreamDataSubmit* streamDataSubmitNew(SSubmitReq* pReq) {
SStreamDataSubmit* pDataSubmit = (SStreamDataSubmit*)taosAllocateQitem(sizeof(SStreamDataSubmit), DEF_QITEM);
if (pDataSubmit == NULL) return NULL;
@@ -111,6 +139,8 @@ static FORCE_INLINE void streamDataSubmitRefDec(SStreamDataSubmit* pDataSubmit)
}
}
+SStreamDataSubmit* streamSubmitRefClone(SStreamDataSubmit* pSubmit);
+
int32_t streamDataBlockEncode(void** buf, const SStreamDataBlock* pOutput);
void* streamDataBlockDecode(const void* buf, SStreamDataBlock* pInput);
@@ -209,8 +239,6 @@ struct SStreamTask {
int32_t nodeId;
SEpSet epSet;
- // source preprocess
-
// exec
STaskExec exec;
@@ -318,8 +346,6 @@ int32_t streamDequeueOutput(SStreamTask* pTask, void** output);
int32_t streamTaskRun(SStreamTask* pTask);
-int32_t streamTaskHandleInput(SStreamTask* pTask, void* data);
-
int32_t streamTaskProcessRunReq(SStreamTask* pTask, SMsgCb* pMsgCb);
int32_t streamProcessDispatchReq(SStreamTask* pTask, SMsgCb* pMsgCb, SStreamDispatchReq* pReq, SRpcMsg* pMsg);
int32_t streamProcessDispatchRsp(SStreamTask* pTask, SMsgCb* pMsgCb, SStreamDispatchRsp* pRsp);
diff --git a/include/os/osDir.h b/include/os/osDir.h
index a4c686e280..9019d4f802 100644
--- a/include/os/osDir.h
+++ b/include/os/osDir.h
@@ -33,8 +33,19 @@ extern "C" {
#ifdef WINDOWS
#define TD_TMP_DIR_PATH "C:\\Windows\\Temp\\"
+#define TD_CFG_DIR_PATH "C:\\TDengine\\cfg\\"
+#define TD_DATA_DIR_PATH "C:\\TDengine\\data\\"
+#define TD_LOG_DIR_PATH "C:\\TDengine\\log\\"
+#elif defined(_TD_DARWIN_64)
+#define TD_TMP_DIR_PATH "/tmp/taosd/"
+#define TD_CFG_DIR_PATH "/usr/local/etc/taos/"
+#define TD_DATA_DIR_PATH "/usr/local/var/lib/taos/"
+#define TD_LOG_DIR_PATH "/usr/local/var/log/taos/"
#else
#define TD_TMP_DIR_PATH "/tmp/"
+#define TD_CFG_DIR_PATH "/etc/taos/"
+#define TD_DATA_DIR_PATH "/var/lib/taos/"
+#define TD_LOG_DIR_PATH "/var/log/taos/"
#endif
typedef struct TdDir *TdDirPtr;
diff --git a/include/util/taoserror.h b/include/util/taoserror.h
index 3669348a18..4550bccbed 100644
--- a/include/util/taoserror.h
+++ b/include/util/taoserror.h
@@ -70,6 +70,7 @@ int32_t* taosGetErrno();
#define TSDB_CODE_NEED_RETRY TAOS_DEF_ERROR_CODE(0, 0x0028)
#define TSDB_CODE_OUT_OF_RPC_MEMORY_QUEUE TAOS_DEF_ERROR_CODE(0, 0x0029)
#define TSDB_CODE_INVALID_TIMESTAMP TAOS_DEF_ERROR_CODE(0, 0x0030)
+#define TSDB_CODE_MSG_DECODE_ERROR TAOS_DEF_ERROR_CODE(0, 0x0031)
#define TSDB_CODE_REF_NO_MEMORY TAOS_DEF_ERROR_CODE(0, 0x0040)
#define TSDB_CODE_REF_FULL TAOS_DEF_ERROR_CODE(0, 0x0041)
@@ -84,6 +85,7 @@ int32_t* taosGetErrno();
#define TSDB_CODE_RPC_NETWORK_UNAVAIL TAOS_DEF_ERROR_CODE(0, 0x0102)
#define TSDB_CODE_RPC_FQDN_ERROR TAOS_DEF_ERROR_CODE(0, 0x0103)
#define TSDB_CODE_RPC_PORT_EADDRINUSE TAOS_DEF_ERROR_CODE(0, 0x0104)
+#define TSDB_CODE_RPC_INDIRECT_NETWORK_UNAVAIL TAOS_DEF_ERROR_CODE(0, 0x0105)
//client
#define TSDB_CODE_TSC_INVALID_OPERATION TAOS_DEF_ERROR_CODE(0, 0x0200)
@@ -183,8 +185,7 @@ int32_t* taosGetErrno();
#define TSDB_CODE_MND_BNODE_NOT_EXIST TAOS_DEF_ERROR_CODE(0, 0x0357)
#define TSDB_CODE_MND_TOO_FEW_MNODES TAOS_DEF_ERROR_CODE(0, 0x0358)
#define TSDB_CODE_MND_TOO_MANY_MNODES TAOS_DEF_ERROR_CODE(0, 0x0359)
-#define TSDB_CODE_MND_MNODE_DEPLOYED TAOS_DEF_ERROR_CODE(0, 0x035A)
-#define TSDB_CODE_MND_CANT_DROP_MASTER TAOS_DEF_ERROR_CODE(0, 0x035B)
+#define TSDB_CODE_MND_CANT_DROP_MASTER TAOS_DEF_ERROR_CODE(0, 0x035A)
// mnode-acct
#define TSDB_CODE_MND_ACCT_ALREADY_EXIST TAOS_DEF_ERROR_CODE(0, 0x0360)
diff --git a/include/util/tdef.h b/include/util/tdef.h
index de139368c9..0ae22d1953 100644
--- a/include/util/tdef.h
+++ b/include/util/tdef.h
@@ -209,7 +209,7 @@ typedef enum ELogicConditionType {
#define TSDB_INDEX_FNAME_LEN (TSDB_DB_FNAME_LEN + TSDB_INDEX_NAME_LEN + TSDB_NAME_DELIMITER_LEN)
#define TSDB_TYPE_STR_MAX_LEN 32
#define TSDB_TABLE_FNAME_LEN (TSDB_DB_FNAME_LEN + TSDB_TABLE_NAME_LEN + TSDB_NAME_DELIMITER_LEN)
-#define TSDB_TOPIC_FNAME_LEN TSDB_TABLE_FNAME_LEN
+#define TSDB_TOPIC_FNAME_LEN (TSDB_ACCT_ID_LEN + TSDB_TABLE_NAME_LEN + TSDB_NAME_DELIMITER_LEN)
#define TSDB_STREAM_FNAME_LEN TSDB_TABLE_FNAME_LEN
#define TSDB_SUBSCRIBE_KEY_LEN (TSDB_CGROUP_LEN + TSDB_TOPIC_FNAME_LEN + 2)
#define TSDB_PARTITION_KEY_LEN (TSDB_SUBSCRIBE_KEY_LEN + 20)
diff --git a/include/util/tencode.h b/include/util/tencode.h
index ffd9ee53dd..a13afd4448 100644
--- a/include/util/tencode.h
+++ b/include/util/tencode.h
@@ -534,6 +534,26 @@ static FORCE_INLINE int32_t tPutI64(uint8_t* p, int64_t v) {
return sizeof(int64_t);
}
+static FORCE_INLINE int32_t tPutFloat(uint8_t* p, float f) {
+ union {
+ uint32_t ui;
+ float f;
+ } v;
+ v.f = f;
+
+ return tPutU32(p, v.ui);
+}
+
+static FORCE_INLINE int32_t tPutDouble(uint8_t* p, double d) {
+ union {
+ uint64_t ui;
+ double d;
+ } v;
+ v.d = d;
+
+ return tPutU64(p, v.ui);
+}
+
static FORCE_INLINE int32_t tPutU16v(uint8_t* p, uint16_t v) { tPutV(p, v); }
static FORCE_INLINE int32_t tPutI16v(uint8_t* p, int16_t v) { return tPutU16v(p, ZIGZAGE(int16_t, v)); }
@@ -623,6 +643,34 @@ static FORCE_INLINE int32_t tGetI64v(uint8_t* p, int64_t* v) {
return n;
}
+static FORCE_INLINE int32_t tGetFloat(uint8_t* p, float* f) {
+ int32_t n = 0;
+
+ union {
+ uint32_t ui;
+ float f;
+ } v;
+
+ n = tGetU32(p, &v.ui);
+
+ *f = v.f;
+ return n;
+}
+
+static FORCE_INLINE int32_t tGetDouble(uint8_t* p, double* d) {
+ int32_t n = 0;
+
+ union {
+ uint64_t ui;
+ double d;
+ } v;
+
+ n = tGetU64(p, &v.ui);
+
+ *d = v.d;
+ return n;
+}
+
// =====================
static FORCE_INLINE int32_t tPutBinary(uint8_t* p, uint8_t* pData, uint32_t nData) {
int n = 0;
@@ -646,6 +694,11 @@ static FORCE_INLINE int32_t tGetBinary(uint8_t* p, uint8_t** ppData, uint32_t* n
return n;
}
+static FORCE_INLINE int32_t tPutCStr(uint8_t* p, char* pData) {
+ return tPutBinary(p, (uint8_t*)pData, strlen(pData) + 1);
+}
+static FORCE_INLINE int32_t tGetCStr(uint8_t* p, char** ppData) { return tGetBinary(p, (uint8_t**)ppData, NULL); }
+
#ifdef __cplusplus
}
#endif
diff --git a/include/util/ttimer.h b/include/util/ttimer.h
index 1022259631..4111a8ca28 100644
--- a/include/util/ttimer.h
+++ b/include/util/ttimer.h
@@ -31,16 +31,16 @@ extern int32_t taosTmrThreads;
void *taosTmrInit(int32_t maxTmr, int32_t resoultion, int32_t longest, const char *label);
+void taosTmrCleanUp(void *handle);
+
tmr_h taosTmrStart(TAOS_TMR_CALLBACK fp, int32_t mseconds, void *param, void *handle);
bool taosTmrStop(tmr_h tmrId);
-bool taosTmrStopA(tmr_h *timerId);
+bool taosTmrStopA(tmr_h *tmrId);
bool taosTmrReset(TAOS_TMR_CALLBACK fp, int32_t mseconds, void *param, void *handle, tmr_h *pTmrId);
-void taosTmrCleanUp(void *handle);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/client/inc/clientInt.h b/source/client/inc/clientInt.h
index ad610603bf..a2305dd45d 100644
--- a/source/client/inc/clientInt.h
+++ b/source/client/inc/clientInt.h
@@ -192,6 +192,7 @@ typedef struct SRequestSendRecvBody {
typedef struct {
int8_t resType;
char topic[TSDB_TOPIC_FNAME_LEN];
+ char db[TSDB_DB_FNAME_LEN];
int32_t vgId;
SSchemaWrapper schema;
int32_t resIter;
@@ -220,7 +221,8 @@ typedef struct SRequestObj {
void* doFetchRows(SRequestObj* pRequest, bool setupOneRowPtr, bool convertUcs4);
void doSetOneRowPtr(SReqResultInfo* pResultInfo);
void setResPrecision(SReqResultInfo* pResInfo, int32_t precision);
-int32_t setQueryResultFromRsp(SReqResultInfo* pResultInfo, const SRetrieveTableRsp* pRsp, bool convertUcs4);
+int32_t setQueryResultFromRsp(SReqResultInfo* pResultInfo, const SRetrieveTableRsp* pRsp, bool convertUcs4,
+ bool freeAfterUse);
void setResSchemaInfo(SReqResultInfo* pResInfo, const SSchema* pSchema, int32_t numOfCols);
void doFreeReqResultInfo(SReqResultInfo* pResInfo);
@@ -242,7 +244,7 @@ static FORCE_INLINE SReqResultInfo* tmqGetNextResInfo(TAOS_RES* res, bool conver
taosMemoryFreeClear(msg->resInfo.length);
taosMemoryFreeClear(msg->resInfo.convertBuf);
}
- setQueryResultFromRsp(&msg->resInfo, pRetrieve, convertUcs4);
+ setQueryResultFromRsp(&msg->resInfo, pRetrieve, convertUcs4, false);
return &msg->resInfo;
}
return NULL;
@@ -320,7 +322,7 @@ SRequestObj* launchQueryImpl(SRequestObj* pRequest, SQuery* pQuery, int32_t code
int32_t getQueryPlan(SRequestObj* pRequest, SQuery* pQuery, SArray** pNodeList);
int32_t scheduleQuery(SRequestObj* pRequest, SQueryPlan* pDag, SArray* pNodeList);
int32_t refreshMeta(STscObj* pTscObj, SRequestObj* pRequest);
-int32_t updateQnodeList(SAppInstInfo*pInfo, SArray* pNodeList);
+int32_t updateQnodeList(SAppInstInfo* pInfo, SArray* pNodeList);
#ifdef __cplusplus
}
diff --git a/source/client/src/clientImpl.c b/source/client/src/clientImpl.c
index 729f53f443..c4bf3b50bf 100644
--- a/source/client/src/clientImpl.c
+++ b/source/client/src/clientImpl.c
@@ -117,7 +117,7 @@ TAOS* taos_connect_internal(const char* ip, const char* user, const char* pass,
SAppInstInfo* p = NULL;
if (pInst == NULL) {
p = taosMemoryCalloc(1, sizeof(struct SAppInstInfo));
- p->mgmtEp = epSet;
+ p->mgmtEp = epSet;
taosThreadMutexInit(&p->qnodeMutex, NULL);
p->pTransporter = openTransporter(user, secretEncrypt, tsNumOfCores);
p->pAppHbMgr = appHbMgrInit(p, key);
@@ -203,7 +203,7 @@ int32_t execLocalCmd(SRequestObj* pRequest, SQuery* pQuery) {
SRetrieveTableRsp* pRsp = NULL;
int32_t code = qExecCommand(pQuery->pRoot, &pRsp);
if (TSDB_CODE_SUCCESS == code && NULL != pRsp) {
- code = setQueryResultFromRsp(&pRequest->body.resInfo, pRsp, false);
+ code = setQueryResultFromRsp(&pRequest->body.resInfo, pRsp, false, false);
}
return code;
}
@@ -230,23 +230,23 @@ int32_t execDdlQuery(SRequestObj* pRequest, SQuery* pQuery) {
}
int compareQueryNodeLoad(const void* elem1, const void* elem2) {
- SQueryNodeLoad *node1 = (SQueryNodeLoad *)elem1;
- SQueryNodeLoad *node2 = (SQueryNodeLoad *)elem2;
+ SQueryNodeLoad* node1 = (SQueryNodeLoad*)elem1;
+ SQueryNodeLoad* node2 = (SQueryNodeLoad*)elem2;
if (node1->load < node2->load) {
return -1;
}
-
+
return node1->load > node2->load;
}
-int32_t updateQnodeList(SAppInstInfo*pInfo, SArray* pNodeList) {
+int32_t updateQnodeList(SAppInstInfo* pInfo, SArray* pNodeList) {
taosThreadMutexLock(&pInfo->qnodeMutex);
if (pInfo->pQnodeList) {
taosArrayDestroy(pInfo->pQnodeList);
pInfo->pQnodeList = NULL;
}
-
+
if (pNodeList) {
pInfo->pQnodeList = taosArrayDup(pNodeList);
taosArraySort(pInfo->pQnodeList, compareQueryNodeLoad);
@@ -257,9 +257,9 @@ int32_t updateQnodeList(SAppInstInfo*pInfo, SArray* pNodeList) {
}
int32_t getQnodeList(SRequestObj* pRequest, SArray** pNodeList) {
- SAppInstInfo*pInfo = pRequest->pTscObj->pAppInfo;
- int32_t code = 0;
-
+ SAppInstInfo* pInfo = pRequest->pTscObj->pAppInfo;
+ int32_t code = 0;
+
taosThreadMutexLock(&pInfo->qnodeMutex);
if (pInfo->pQnodeList) {
*pNodeList = taosArrayDup(pInfo->pQnodeList);
@@ -267,14 +267,14 @@ int32_t getQnodeList(SRequestObj* pRequest, SArray** pNodeList) {
taosThreadMutexUnlock(&pInfo->qnodeMutex);
if (NULL == *pNodeList) {
- SEpSet mgmtEpSet = getEpSet_s(&pRequest->pTscObj->pAppInfo->mgmtEp);
- SCatalog* pCatalog = NULL;
+ SEpSet mgmtEpSet = getEpSet_s(&pRequest->pTscObj->pAppInfo->mgmtEp);
+ SCatalog* pCatalog = NULL;
code = catalogGetHandle(pRequest->pTscObj->pAppInfo->clusterId, &pCatalog);
if (TSDB_CODE_SUCCESS == code) {
*pNodeList = taosArrayInit(5, sizeof(SQueryNodeLoad));
code = catalogGetQnodeList(pCatalog, pRequest->pTscObj->pAppInfo->pTransporter, &mgmtEpSet, *pNodeList);
}
-
+
if (TSDB_CODE_SUCCESS == code && *pNodeList) {
code = updateQnodeList(pInfo, *pNodeList);
}
@@ -342,7 +342,7 @@ void setResPrecision(SReqResultInfo* pResInfo, int32_t precision) {
int32_t scheduleAsyncQuery(SRequestObj* pRequest, SQueryPlan* pDag, SArray* pNodeList) {
void* pTransporter = pRequest->pTscObj->pAppInfo->pTransporter;
-
+
tsem_init(&schdRspSem, 0, 0);
SQueryResult res = {.code = 0, .numOfRows = 0};
@@ -362,7 +362,7 @@ int32_t scheduleAsyncQuery(SRequestObj* pRequest, SQueryPlan* pDag, SArray* pNod
return pRequest->code;
} else {
tsem_wait(&schdRspSem);
-
+
if (res.code) {
code = res.code;
} else {
@@ -384,7 +384,6 @@ int32_t scheduleAsyncQuery(SRequestObj* pRequest, SQueryPlan* pDag, SArray* pNod
return pRequest->code;
}
-
int32_t scheduleQuery(SRequestObj* pRequest, SQueryPlan* pDag, SArray* pNodeList) {
void* pTransporter = pRequest->pTscObj->pAppInfo->pTransporter;
@@ -807,7 +806,7 @@ void updateTargetEpSet(SMsgSendInfo* pSendInfo, STscObj* pTscObj, SRpcMsg* pMsg,
if (NULL == pEpSet) {
return;
}
-
+
switch (pSendInfo->target.type) {
case TARGET_TYPE_MNODE:
if (NULL == pTscObj) {
@@ -815,7 +814,7 @@ void updateTargetEpSet(SMsgSendInfo* pSendInfo, STscObj* pTscObj, SRpcMsg* pMsg,
return;
}
- updateEpSet_s(&pTscObj->pAppInfo->mgmtEp, pEpSet);
+ updateEpSet_s(&pTscObj->pAppInfo->mgmtEp, pEpSet);
break;
case TARGET_TYPE_VNODE: {
if (NULL == pTscObj) {
@@ -824,12 +823,13 @@ void updateTargetEpSet(SMsgSendInfo* pSendInfo, STscObj* pTscObj, SRpcMsg* pMsg,
}
SCatalog* pCatalog = NULL;
- int32_t code = catalogGetHandle(pTscObj->pAppInfo->clusterId, &pCatalog);
+ int32_t code = catalogGetHandle(pTscObj->pAppInfo->clusterId, &pCatalog);
if (code != TSDB_CODE_SUCCESS) {
- tscError("fail to get catalog handle, clusterId:%" PRIx64 ", error %s", pTscObj->pAppInfo->clusterId, tstrerror(code));
+ tscError("fail to get catalog handle, clusterId:%" PRIx64 ", error %s", pTscObj->pAppInfo->clusterId,
+ tstrerror(code));
return;
}
-
+
catalogUpdateVgEpSet(pCatalog, pSendInfo->target.dbFName, pSendInfo->target.vgId, pEpSet);
break;
}
@@ -839,12 +839,11 @@ void updateTargetEpSet(SMsgSendInfo* pSendInfo, STscObj* pTscObj, SRpcMsg* pMsg,
}
}
-
void processMsgFromServer(void* parent, SRpcMsg* pMsg, SEpSet* pEpSet) {
SMsgSendInfo* pSendInfo = (SMsgSendInfo*)pMsg->info.ahandle;
assert(pMsg->info.ahandle != NULL);
SRequestObj* pRequest = NULL;
- STscObj* pTscObj = NULL;
+ STscObj* pTscObj = NULL;
if (pSendInfo->requestObjRefId != 0) {
SRequestObj* pRequest = (SRequestObj*)taosAcquireRef(clientReqRefPool, pSendInfo->requestObjRefId);
@@ -971,7 +970,8 @@ void* doAsyncFetchRows(SRequestObj* pRequest, bool setupOneRowPtr, bool convertU
return NULL;
}
- pRequest->code = setQueryResultFromRsp(&pRequest->body.resInfo, (SRetrieveTableRsp*)pResInfo->pData, convertUcs4);
+ pRequest->code =
+ setQueryResultFromRsp(&pRequest->body.resInfo, (SRetrieveTableRsp*)pResInfo->pData, convertUcs4, true);
if (pRequest->code != TSDB_CODE_SUCCESS) {
pResultInfo->numOfRows = 0;
return NULL;
@@ -993,9 +993,8 @@ void* doAsyncFetchRows(SRequestObj* pRequest, bool setupOneRowPtr, bool convertU
return pResultInfo->row;
}
-
void* doFetchRows(SRequestObj* pRequest, bool setupOneRowPtr, bool convertUcs4) {
- //return doAsyncFetchRows(pRequest, setupOneRowPtr, convertUcs4);
+ // return doAsyncFetchRows(pRequest, setupOneRowPtr, convertUcs4);
assert(pRequest != NULL);
SReqResultInfo* pResultInfo = &pRequest->body.resInfo;
@@ -1013,7 +1012,8 @@ void* doFetchRows(SRequestObj* pRequest, bool setupOneRowPtr, bool convertUcs4)
return NULL;
}
- pRequest->code = setQueryResultFromRsp(&pRequest->body.resInfo, (SRetrieveTableRsp*)pResInfo->pData, convertUcs4);
+ pRequest->code =
+ setQueryResultFromRsp(&pRequest->body.resInfo, (SRetrieveTableRsp*)pResInfo->pData, convertUcs4, true);
if (pRequest->code != TSDB_CODE_SUCCESS) {
pResultInfo->numOfRows = 0;
return NULL;
@@ -1057,27 +1057,20 @@ static char* parseTagDatatoJson(void* p) {
goto end;
}
- int16_t nCols = kvRowNCols(p);
+ SArray* pTagVals = NULL;
+ if (tTagToValArray((const STag*)p, &pTagVals) != 0) {
+ goto end;
+ }
+
+ int16_t nCols = taosArrayGetSize(pTagVals);
char tagJsonKey[256] = {0};
for (int j = 0; j < nCols; ++j) {
- SColIdx* pColIdx = kvRowColIdxAt(p, j);
- char* val = (char*)(kvRowColVal(p, pColIdx));
- if (j == 0) {
- if (*val == TSDB_DATA_TYPE_NULL) {
- string = taosMemoryCalloc(1, 8);
- sprintf(string, "%s", TSDB_DATA_NULL_STR_L);
- goto end;
- }
- continue;
- }
-
+ STagVal* pTagVal = (STagVal*)taosArrayGet(pTagVals, j);
// json key encode by binary
memset(tagJsonKey, 0, sizeof(tagJsonKey));
- memcpy(tagJsonKey, varDataVal(val), varDataLen(val));
+ memcpy(tagJsonKey, pTagVal->pKey, strlen(pTagVal->pKey));
// json value
- val += varDataTLen(val);
- char* realData = POINTER_SHIFT(val, CHAR_BYTES);
- char type = *val;
+ char type = pTagVal->type;
if (type == TSDB_DATA_TYPE_NULL) {
cJSON* value = cJSON_CreateNull();
if (value == NULL) {
@@ -1086,11 +1079,12 @@ static char* parseTagDatatoJson(void* p) {
cJSON_AddItemToObject(json, tagJsonKey, value);
} else if (type == TSDB_DATA_TYPE_NCHAR) {
cJSON* value = NULL;
- if (varDataLen(realData) > 0) {
- char* tagJsonValue = taosMemoryCalloc(varDataLen(realData), 1);
- int32_t length = taosUcs4ToMbs((TdUcs4*)varDataVal(realData), varDataLen(realData), tagJsonValue);
+ if (pTagVal->nData > 0) {
+ char* tagJsonValue = taosMemoryCalloc(pTagVal->nData, 1);
+ int32_t length = taosUcs4ToMbs((TdUcs4*)pTagVal->pData, pTagVal->nData, tagJsonValue);
if (length < 0) {
- tscError("charset:%s to %s. val:%s convert json value failed.", DEFAULT_UNICODE_ENCODEC, tsCharset, val);
+ tscError("charset:%s to %s. val:%s convert json value failed.", DEFAULT_UNICODE_ENCODEC, tsCharset,
+ pTagVal->pData);
taosMemoryFree(tagJsonValue);
goto end;
}
@@ -1099,7 +1093,7 @@ static char* parseTagDatatoJson(void* p) {
if (value == NULL) {
goto end;
}
- } else if (varDataLen(realData) == 0) {
+ } else if (pTagVal->nData == 0) {
value = cJSON_CreateString("");
} else {
ASSERT(0);
@@ -1107,22 +1101,14 @@ static char* parseTagDatatoJson(void* p) {
cJSON_AddItemToObject(json, tagJsonKey, value);
} else if (type == TSDB_DATA_TYPE_DOUBLE) {
- double jsonVd = *(double*)(realData);
+ double jsonVd = *(double*)(&pTagVal->i64);
cJSON* value = cJSON_CreateNumber(jsonVd);
if (value == NULL) {
goto end;
}
cJSON_AddItemToObject(json, tagJsonKey, value);
- // }else if(type == TSDB_DATA_TYPE_BIGINT){
- // int64_t jsonVd = *(int64_t*)(realData);
- // cJSON* value = cJSON_CreateNumber((double)jsonVd);
- // if (value == NULL)
- // {
- // goto end;
- // }
- // cJSON_AddItemToObject(json, tagJsonKey, value);
} else if (type == TSDB_DATA_TYPE_BOOL) {
- char jsonVd = *(char*)(realData);
+ char jsonVd = *(char*)(&pTagVal->i64);
cJSON* value = cJSON_CreateBool(jsonVd);
if (value == NULL) {
goto end;
@@ -1187,7 +1173,7 @@ static int32_t doConvertUCS4(SReqResultInfo* pResultInfo, int32_t numOfRows, int
if (jsonInnerType == TSDB_DATA_TYPE_NULL) {
sprintf(varDataVal(dst), "%s", TSDB_DATA_NULL_STR_L);
varDataSetLen(dst, strlen(varDataVal(dst)));
- } else if (jsonInnerType == TSDB_DATA_TYPE_JSON) {
+ } else if (jsonInnerType == TD_TAG_JSON) {
char* jsonString = parseTagDatatoJson(jsonInnerData);
STR_TO_VARSTR(dst, jsonString);
taosMemoryFree(jsonString);
@@ -1206,10 +1192,6 @@ static int32_t doConvertUCS4(SReqResultInfo* pResultInfo, int32_t numOfRows, int
double jsonVd = *(double*)(jsonInnerData);
sprintf(varDataVal(dst), "%.9lf", jsonVd);
varDataSetLen(dst, strlen(varDataVal(dst)));
- } else if (jsonInnerType == TSDB_DATA_TYPE_BIGINT) {
- int64_t jsonVd = *(int64_t*)(jsonInnerData);
- sprintf(varDataVal(dst), "%" PRId64, jsonVd);
- varDataSetLen(dst, strlen(varDataVal(dst)));
} else if (jsonInnerType == TSDB_DATA_TYPE_BOOL) {
sprintf(varDataVal(dst), "%s", (*((char*)jsonInnerData) == 1) ? "true" : "false");
varDataSetLen(dst, strlen(varDataVal(dst)));
@@ -1320,11 +1302,12 @@ void resetConnectDB(STscObj* pTscObj) {
taosThreadMutexUnlock(&pTscObj->mutex);
}
-int32_t setQueryResultFromRsp(SReqResultInfo* pResultInfo, const SRetrieveTableRsp* pRsp, bool convertUcs4) {
+int32_t setQueryResultFromRsp(SReqResultInfo* pResultInfo, const SRetrieveTableRsp* pRsp, bool convertUcs4,
+ bool freeAfterUse) {
assert(pResultInfo != NULL && pRsp != NULL);
- taosMemoryFreeClear(pResultInfo->pRspMsg);
-
+ if (freeAfterUse) taosMemoryFreeClear(pResultInfo->pRspMsg);
+
pResultInfo->pRspMsg = (const char*)pRsp;
pResultInfo->pData = (void*)pRsp->data;
pResultInfo->numOfRows = htonl(pRsp->numOfRows);
diff --git a/source/client/src/tmq.c b/source/client/src/tmq.c
index 416d1a6f26..c2170631c2 100644
--- a/source/client/src/tmq.c
+++ b/source/client/src/tmq.c
@@ -143,6 +143,7 @@ typedef struct {
typedef struct {
// subscribe info
char* topicName;
+ char db[TSDB_DB_FNAME_LEN];
SArray* vgs; // SArray
@@ -1039,6 +1040,7 @@ bool tmqUpdateEp(tmq_t* tmq, int32_t epoch, SMqAskEpRsp* pRsp) {
topic.schema = pTopicEp->schema;
taosHashClear(pHash);
topic.topicName = strdup(pTopicEp->topic);
+ tstrncpy(topic.db, pTopicEp->db, TSDB_DB_FNAME_LEN);
tscDebug("consumer %ld update topic: %s", tmq->consumerId, topic.topicName);
int32_t topicNumCur = taosArrayGetSize(tmq->clientTopics);
@@ -1283,7 +1285,8 @@ SMqPollReq* tmqBuildConsumeReqImpl(tmq_t* tmq, int64_t timeout, SMqClientTopic*
SMqRspObj* tmqBuildRspFromWrapper(SMqPollRspWrapper* pWrapper) {
SMqRspObj* pRspObj = taosMemoryCalloc(1, sizeof(SMqRspObj));
pRspObj->resType = RES_TYPE__TMQ;
- strncpy(pRspObj->topic, pWrapper->topicHandle->topicName, TSDB_TOPIC_FNAME_LEN);
+ tstrncpy(pRspObj->topic, pWrapper->topicHandle->topicName, TSDB_TOPIC_FNAME_LEN);
+ tstrncpy(pRspObj->db, pWrapper->topicHandle->db, TSDB_DB_FNAME_LEN);
pRspObj->vgId = pWrapper->vgHandle->vgId;
pRspObj->resIter = -1;
memcpy(&pRspObj->rsp, &pWrapper->msg, sizeof(SMqDataBlkRsp));
@@ -1506,6 +1509,15 @@ const char* tmq_get_topic_name(TAOS_RES* res) {
}
}
+const char* tmq_get_db_name(TAOS_RES* res) {
+ if (TD_RES_TMQ(res)) {
+ SMqRspObj* pRspObj = (SMqRspObj*)res;
+ return strchr(pRspObj->db, '.') + 1;
+ } else {
+ return NULL;
+ }
+}
+
int32_t tmq_get_vgroup_id(TAOS_RES* res) {
if (TD_RES_TMQ(res)) {
SMqRspObj* pRspObj = (SMqRspObj*)res;
diff --git a/source/common/src/systable.c b/source/common/src/systable.c
index 8207ffb22f..b163ac32bf 100644
--- a/source/common/src/systable.c
+++ b/source/common/src/systable.c
@@ -36,6 +36,7 @@ static const SSysDbTableSchema mnodesSchema[] = {
{.name = "id", .bytes = 4, .type = TSDB_DATA_TYPE_INT},
{.name = "endpoint", .bytes = TSDB_EP_LEN + VARSTR_HEADER_SIZE, .type = TSDB_DATA_TYPE_VARCHAR},
{.name = "role", .bytes = 12 + VARSTR_HEADER_SIZE, .type = TSDB_DATA_TYPE_VARCHAR},
+ {.name = "status", .bytes = 9 + VARSTR_HEADER_SIZE, .type = TSDB_DATA_TYPE_VARCHAR},
{.name = "create_time", .bytes = 8, .type = TSDB_DATA_TYPE_TIMESTAMP},
};
diff --git a/source/common/src/tdatablock.c b/source/common/src/tdatablock.c
index 349564ae28..9d16de43b3 100644
--- a/source/common/src/tdatablock.c
+++ b/source/common/src/tdatablock.c
@@ -116,22 +116,23 @@ int32_t colDataAppend(SColumnInfoData* pColumnInfoData, uint32_t currentRow, con
int32_t type = pColumnInfoData->info.type;
if (IS_VAR_DATA_TYPE(type)) {
- int32_t dataLen = varDataTLen(pData);
+ int32_t dataLen = 0;
if (type == TSDB_DATA_TYPE_JSON) {
if (*pData == TSDB_DATA_TYPE_NULL) {
- dataLen = 0;
- } else if (*pData == TSDB_DATA_TYPE_NCHAR) {
- dataLen = varDataTLen(pData + CHAR_BYTES);
- } else if (*pData == TSDB_DATA_TYPE_DOUBLE) {
- dataLen = DOUBLE_BYTES;
- } else if (*pData == TSDB_DATA_TYPE_BOOL) {
dataLen = CHAR_BYTES;
- } else if (*pData == TSDB_DATA_TYPE_JSON) {
- dataLen = kvRowLen(pData + CHAR_BYTES);
+ } else if (*pData == TSDB_DATA_TYPE_NCHAR) {
+ dataLen = varDataTLen(pData + CHAR_BYTES) + CHAR_BYTES;
+ } else if (*pData == TSDB_DATA_TYPE_DOUBLE) {
+ dataLen = DOUBLE_BYTES + CHAR_BYTES;
+ } else if (*pData == TSDB_DATA_TYPE_BOOL) {
+ dataLen = CHAR_BYTES + CHAR_BYTES;
+ } else if (*pData == TD_TAG_JSON) { // json string
+ dataLen = ((STag*)(pData))->len;
} else {
ASSERT(0);
}
- dataLen += CHAR_BYTES;
+ }else {
+ dataLen = varDataTLen(pData);
}
SVarColAttr* pAttr = &pColumnInfoData->varmeta;
@@ -1634,6 +1635,11 @@ int32_t buildSubmitReqFromDataBlock(SSubmitReq** pReq, const SArray* pDataBlocks
SSubmitReq* tdBlockToSubmit(const SArray* pBlocks, const STSchema* pTSchema, bool createTb, int64_t suid,
const char* stbFullName, int32_t vgId) {
SSubmitReq* ret = NULL;
+ SArray* tagArray = taosArrayInit(1, sizeof(STagVal));
+ if(!tagArray) {
+ terrno = TSDB_CODE_OUT_OF_MEMORY;
+ return NULL;
+ }
// cal size
int32_t cap = sizeof(SSubmitReq);
@@ -1655,18 +1661,33 @@ SSubmitReq* tdBlockToSubmit(const SArray* pBlocks, const STSchema* pTSchema, boo
createTbReq.type = TSDB_CHILD_TABLE;
createTbReq.ctb.suid = suid;
- SKVRowBuilder kvRowBuilder = {0};
- if (tdInitKVRowBuilder(&kvRowBuilder) < 0) {
- ASSERT(0);
+
+
+ STagVal tagVal = {.cid = 1,
+ .type = TSDB_DATA_TYPE_UBIGINT,
+ .pData = (uint8_t*)&pDataBlock->info.groupId,
+ .nData = sizeof(uint64_t)};
+ STag* pTag = NULL;
+ taosArrayClear(tagArray);
+ taosArrayPush(tagArray, &tagVal);
+ tTagNew(tagArray, 1, false, &pTag);
+ if (!pTag) {
+ tdDestroySVCreateTbReq(&createTbReq);
+ taosArrayDestroy(tagArray);
+ return NULL;
}
- tdAddColToKVRow(&kvRowBuilder, 1, &pDataBlock->info.groupId, sizeof(uint64_t));
- createTbReq.ctb.pTag = tdGetKVRowFromBuilder(&kvRowBuilder);
- tdDestroyKVRowBuilder(&kvRowBuilder);
+ createTbReq.ctb.pTag = (uint8_t*)pTag;
int32_t code;
tEncodeSize(tEncodeSVCreateTbReq, &createTbReq, schemaLen, code);
- if (code < 0) return NULL;
- taosMemoryFree(cname);
+
+ tdDestroySVCreateTbReq(&createTbReq);
+
+ if (code < 0) {
+ tdDestroySVCreateTbReq(&createTbReq);
+ taosArrayDestroy(tagArray);
+ return NULL;
+ }
}
cap += sizeof(SSubmitBlk) + schemaLen + rows * maxLen;
@@ -1709,22 +1730,42 @@ SSubmitReq* tdBlockToSubmit(const SArray* pBlocks, const STSchema* pTSchema, boo
createTbReq.type = TSDB_CHILD_TABLE;
createTbReq.ctb.suid = suid;
- SKVRowBuilder kvRowBuilder = {0};
- if (tdInitKVRowBuilder(&kvRowBuilder) < 0) {
- ASSERT(0);
+ STagVal tagVal = {.cid = 1,
+ .type = TSDB_DATA_TYPE_UBIGINT,
+ .pData = (uint8_t*)&pDataBlock->info.groupId,
+ .nData = sizeof(uint64_t)};
+ taosArrayClear(tagArray);
+ taosArrayPush(tagArray, &tagVal);
+ STag* pTag = NULL;
+ tTagNew(tagArray, 1, false, &pTag);
+ if (!pTag) {
+ tdDestroySVCreateTbReq(&createTbReq);
+ taosArrayDestroy(tagArray);
+ taosMemoryFreeClear(ret);
+ return NULL;
}
- tdAddColToKVRow(&kvRowBuilder, 1, &pDataBlock->info.groupId, sizeof(uint64_t));
- createTbReq.ctb.pTag = tdGetKVRowFromBuilder(&kvRowBuilder);
- tdDestroyKVRowBuilder(&kvRowBuilder);
+ createTbReq.ctb.pTag = (uint8_t*)pTag;
int32_t code;
tEncodeSize(tEncodeSVCreateTbReq, &createTbReq, schemaLen, code);
- if (code < 0) return NULL;
+ if (code < 0) {
+ tdDestroySVCreateTbReq(&createTbReq);
+ taosArrayDestroy(tagArray);
+ taosMemoryFreeClear(ret);
+ return NULL;
+ }
SEncoder encoder = {0};
tEncoderInit(&encoder, blockData, schemaLen);
- if (tEncodeSVCreateTbReq(&encoder, &createTbReq) < 0) return NULL;
+ code = tEncodeSVCreateTbReq(&encoder, &createTbReq);
tEncoderClear(&encoder);
+ tdDestroySVCreateTbReq(&createTbReq);
+
+ if (code < 0) {
+ taosArrayDestroy(tagArray);
+ taosMemoryFreeClear(ret);
+ return NULL;
+ }
}
blkHead->schemaLen = htonl(schemaLen);
@@ -1759,5 +1800,6 @@ SSubmitReq* tdBlockToSubmit(const SArray* pBlocks, const STSchema* pTSchema, boo
}
ret->length = htonl(ret->length);
+ taosArrayDestroy(tagArray);
return ret;
}
diff --git a/source/common/src/tdataformat.c b/source/common/src/tdataformat.c
index e8d7e3ac09..65daee6508 100644
--- a/source/common/src/tdataformat.c
+++ b/source/common/src/tdataformat.c
@@ -19,31 +19,15 @@
#include "tdatablock.h"
#include "tlog.h"
-typedef struct SKVIdx {
- int32_t cid;
- int32_t offset;
-} SKVIdx;
+static int32_t tGetTagVal(uint8_t *p, STagVal *pTagVal, int8_t isJson);
#pragma pack(push, 1)
typedef struct {
int16_t nCols;
- SKVIdx idx[];
+ uint8_t idx[];
} STSKVRow;
#pragma pack(pop)
-typedef struct STagIdx {
- int16_t cid;
- uint16_t offset;
-} STagIdx;
-
-#pragma pack(push, 1)
-struct STag {
- uint16_t len;
- uint16_t nTag;
- STagIdx idx[];
-};
-#pragma pack(pop)
-
#define TSROW_IS_KV_ROW(r) ((r)->flags & TSROW_KV_ROW)
#define BIT1_SIZE(n) (((n)-1) / 8 + 1)
#define BIT2_SIZE(n) (((n)-1) / 4 + 1)
@@ -54,7 +38,507 @@ struct STag {
static FORCE_INLINE int tSKVIdxCmprFn(const void *p1, const void *p2);
-// STSRow2
+// SValue
+static FORCE_INLINE int32_t tPutValue(uint8_t *p, SValue *pValue, int8_t type) {
+ int32_t n = 0;
+
+ if (IS_VAR_DATA_TYPE(type)) {
+ n += tPutBinary(p ? p + n : p, pValue->pData, pValue->nData);
+ } else {
+ switch (type) {
+ case TSDB_DATA_TYPE_BOOL:
+ n += tPutI8(p ? p + n : p, pValue->i8 ? 1 : 0);
+ break;
+ case TSDB_DATA_TYPE_TINYINT:
+ n += tPutI8(p ? p + n : p, pValue->i8);
+ break;
+ case TSDB_DATA_TYPE_SMALLINT:
+ n += tPutI16(p ? p + n : p, pValue->i16);
+ break;
+ case TSDB_DATA_TYPE_INT:
+ n += tPutI32(p ? p + n : p, pValue->i32);
+ break;
+ case TSDB_DATA_TYPE_BIGINT:
+ n += tPutI64(p ? p + n : p, pValue->i64);
+ break;
+ case TSDB_DATA_TYPE_FLOAT:
+ n += tPutFloat(p ? p + n : p, pValue->f);
+ break;
+ case TSDB_DATA_TYPE_DOUBLE:
+ n += tPutDouble(p ? p + n : p, pValue->d);
+ break;
+ case TSDB_DATA_TYPE_TIMESTAMP:
+ n += tPutI64(p ? p + n : p, pValue->ts);
+ break;
+ case TSDB_DATA_TYPE_UTINYINT:
+ n += tPutU8(p ? p + n : p, pValue->u8);
+ break;
+ case TSDB_DATA_TYPE_USMALLINT:
+ n += tPutU16(p ? p + n : p, pValue->u16);
+ break;
+ case TSDB_DATA_TYPE_UINT:
+ n += tPutU32(p ? p + n : p, pValue->u32);
+ break;
+ case TSDB_DATA_TYPE_UBIGINT:
+ n += tPutU64(p ? p + n : p, pValue->u64);
+ break;
+ default:
+ ASSERT(0);
+ }
+ }
+
+ return n;
+}
+
+static FORCE_INLINE int32_t tGetValue(uint8_t *p, SValue *pValue, int8_t type) {
+ int32_t n = 0;
+
+ if (IS_VAR_DATA_TYPE(type)) {
+ n += tGetBinary(p, &pValue->pData, pValue ? &pValue->nData : NULL);
+ } else {
+ switch (type) {
+ case TSDB_DATA_TYPE_BOOL:
+ n += tGetI8(p, &pValue->i8);
+ break;
+ case TSDB_DATA_TYPE_TINYINT:
+ n += tGetI8(p, &pValue->i8);
+ break;
+ case TSDB_DATA_TYPE_SMALLINT:
+ n += tGetI16(p, &pValue->i16);
+ break;
+ case TSDB_DATA_TYPE_INT:
+ n += tGetI32(p, &pValue->i32);
+ break;
+ case TSDB_DATA_TYPE_BIGINT:
+ n += tGetI64(p, &pValue->i64);
+ break;
+ case TSDB_DATA_TYPE_FLOAT:
+ n += tGetFloat(p, &pValue->f);
+ break;
+ case TSDB_DATA_TYPE_DOUBLE:
+ n += tGetDouble(p, &pValue->d);
+ break;
+ case TSDB_DATA_TYPE_TIMESTAMP:
+ n += tGetI64(p, &pValue->ts);
+ break;
+ case TSDB_DATA_TYPE_UTINYINT:
+ n += tGetU8(p, &pValue->u8);
+ break;
+ case TSDB_DATA_TYPE_USMALLINT:
+ n += tGetU16(p, &pValue->u16);
+ break;
+ case TSDB_DATA_TYPE_UINT:
+ n += tGetU32(p, &pValue->u32);
+ break;
+ case TSDB_DATA_TYPE_UBIGINT:
+ n += tGetU64(p, &pValue->u64);
+ break;
+ default:
+ ASSERT(0);
+ }
+ }
+
+ return n;
+}
+
+// STSRow2 ========================================================================
+static void tTupleTSRowNew(SArray *pArray, STSchema *pTSchema, STSRow2 *pRow) {
+ int32_t nColVal = taosArrayGetSize(pArray);
+ STColumn *pTColumn;
+ SColVal *pColVal;
+
+ ASSERT(nColVal > 0);
+
+ pRow->sver = pTSchema->version;
+
+ // ts
+ pTColumn = &pTSchema->columns[0];
+ pColVal = (SColVal *)taosArrayGet(pArray, 0);
+
+ ASSERT(pTColumn->colId == 0 && pColVal->cid == 0);
+ ASSERT(pTColumn->type == TSDB_DATA_TYPE_TIMESTAMP);
+
+ pRow->ts = pColVal->value.ts;
+
+ // other fields
+ int32_t iColVal = 1;
+ int32_t bidx;
+ uint32_t nv = 0;
+ uint8_t *pb = NULL;
+ uint8_t *pf = NULL;
+ uint8_t *pv = NULL;
+ uint8_t flags = 0;
+ for (int32_t iColumn = 1; iColumn < pTSchema->numOfCols; iColumn++) {
+ bidx = iColumn - 1;
+ pTColumn = &pTSchema->columns[iColumn];
+
+ if (iColVal < nColVal) {
+ pColVal = (SColVal *)taosArrayGet(pArray, iColVal);
+ } else {
+ pColVal = NULL;
+ }
+
+ if (pColVal) {
+ if (pColVal->cid == pTColumn->colId) {
+ iColVal++;
+ if (pColVal->isNone) {
+ goto _set_none;
+ } else if (pColVal->isNull) {
+ goto _set_null;
+ } else {
+ goto _set_value;
+ }
+ } else if (pColVal->cid > pTColumn->colId) {
+ goto _set_none;
+ } else {
+ ASSERT(0);
+ }
+ } else {
+ goto _set_none;
+ }
+
+ _set_none:
+ flags |= TSROW_HAS_NONE;
+ // SET_BIT2(pb, bidx, 0); (todo)
+ continue;
+
+ _set_null:
+ flags != TSROW_HAS_NULL;
+ // SET_BIT2(pb, bidx, 1); (todo)
+ continue;
+
+ _set_value:
+ flags != TSROW_HAS_VAL;
+ // SET_BIT2(pb, bidx, 2); (todo)
+ if (IS_VAR_DATA_TYPE(pTColumn->type)) {
+ // nv += tPutColVal(pv ? pv + nv : pv, pColVal, pTColumn->type, 1);
+ } else {
+ // tPutColVal(pf ? pf + pTColumn->offset : pf, pColVal, pTColumn->type, 1);
+ }
+ continue;
+ }
+
+ ASSERT(flags);
+ switch (flags & 0xf) {
+ case TSROW_HAS_NONE:
+ case TSROW_HAS_NULL:
+ pRow->nData = 0;
+ break;
+ case TSROW_HAS_VAL:
+ pRow->nData = pTSchema->flen + nv;
+ break;
+ case TSROW_HAS_NULL | TSROW_HAS_NONE:
+ pRow->nData = BIT1_SIZE(pTSchema->numOfCols - 1);
+ break;
+ case TSROW_HAS_VAL | TSROW_HAS_NONE:
+ case TSROW_HAS_VAL | TSROW_HAS_NULL:
+ pRow->nData = BIT1_SIZE(pTSchema->numOfCols - 1) + pTSchema->flen + nv;
+ break;
+ case TSROW_HAS_VAL | TSROW_HAS_NULL | TSROW_HAS_NONE:
+ pRow->nData = BIT2_SIZE(pTSchema->numOfCols - 1) + pTSchema->flen + nv;
+ break;
+ default:
+ break;
+ }
+}
+
+static void tMapTSRowNew(SArray *pArray, STSchema *pTSchema, STSRow2 *pRow) {
+ int32_t nColVal = taosArrayGetSize(pArray);
+ STColumn *pTColumn;
+ SColVal *pColVal;
+
+ ASSERT(nColVal > 0);
+
+ pRow->sver = pTSchema->version;
+
+ // ts
+ pTColumn = &pTSchema->columns[0];
+ pColVal = (SColVal *)taosArrayGet(pArray, 0);
+
+ ASSERT(pTColumn->colId == 0 && pColVal->cid == 0);
+ ASSERT(pTColumn->type == TSDB_DATA_TYPE_TIMESTAMP);
+
+ pRow->ts = pColVal->value.ts;
+
+ // other fields
+ int32_t iColVal = 1;
+ uint32_t nv = 0;
+ uint8_t *pv = NULL;
+ uint8_t *pidx = NULL;
+ uint8_t flags = 0;
+ int16_t nCol = 0;
+ for (int32_t iColumn = 1; iColumn < pTSchema->numOfCols; iColumn++) {
+ pTColumn = &pTSchema->columns[iColumn];
+
+ if (iColVal < nColVal) {
+ pColVal = (SColVal *)taosArrayGet(pArray, iColVal);
+ } else {
+ pColVal = NULL;
+ }
+
+ if (pColVal) {
+ if (pColVal->cid == pTColumn->colId) {
+ iColVal++;
+ if (pColVal->isNone) {
+ goto _set_none;
+ } else if (pColVal->isNull) {
+ goto _set_null;
+ } else {
+ goto _set_value;
+ }
+ } else if (pColVal->cid > pTColumn->colId) {
+ goto _set_none;
+ } else {
+ ASSERT(0);
+ }
+ } else {
+ goto _set_none;
+ }
+
+ _set_none:
+ flags |= TSROW_HAS_NONE;
+ continue;
+
+ _set_null:
+ flags != TSROW_HAS_NULL;
+ pidx[nCol++] = nv;
+ // nv += tPutColVal(pv ? pv + nv : pv, pColVal, pTColumn->type, 0);
+ continue;
+
+ _set_value:
+ flags != TSROW_HAS_VAL;
+ pidx[nCol++] = nv;
+ // nv += tPutColVal(pv ? pv + nv : pv, pColVal, pTColumn->type, 0);
+ continue;
+ }
+
+ if (nv <= UINT8_MAX) {
+ // small
+ } else if (nv <= UINT16_MAX) {
+ // mid
+ } else {
+ // large
+ }
+}
+
+// try-decide-build
+int32_t tTSRowNew(SArray *pArray, STSchema *pTSchema, STSRow2 **ppRow) {
+ int32_t code = 0;
+ STSRow2 rowT = {0};
+ STSRow2 rowM = {0};
+
+ // try
+ tTupleTSRowNew(pArray, pTSchema, &rowT);
+ tMapTSRowNew(pArray, pTSchema, &rowM);
+
+ // decide & build
+ if (rowT.nData <= rowM.nData) {
+ tTupleTSRowNew(pArray, pTSchema, &rowT);
+ } else {
+ tMapTSRowNew(pArray, pTSchema, &rowM);
+ }
+
+ return code;
+}
+
+int32_t tTSRowClone(const STSRow2 *pRow, STSRow2 **ppRow) {
+ int32_t code = 0;
+
+ (*ppRow) = (STSRow2 *)taosMemoryMalloc(sizeof(**ppRow));
+ if (*ppRow == NULL) {
+ code = TSDB_CODE_OUT_OF_MEMORY;
+ goto _exit;
+ }
+ **ppRow = *pRow;
+ (*ppRow)->pData = NULL;
+
+ if (pRow->nData) {
+ (*ppRow)->pData = taosMemoryMalloc(pRow->nData);
+ if ((*ppRow)->pData == NULL) {
+ taosMemoryFree(*ppRow);
+ code = TSDB_CODE_OUT_OF_MEMORY;
+ goto _exit;
+ }
+ memcpy((*ppRow)->pData, pRow->pData, pRow->nData);
+ }
+
+_exit:
+ return code;
+}
+
+void tTSRowFree(STSRow2 *pRow) {
+ if (pRow) {
+ if (pRow->pData) taosMemoryFree(pRow->pData);
+ taosMemoryFree(pRow);
+ }
+}
+
+void tTSRowGet(STSRow2 *pRow, STSchema *pTSchema, int32_t iCol, SColVal *pColVal) {
+ uint8_t isTuple = (pRow->flags & 0xf0 == 0) ? 1 : 0;
+ STColumn *pTColumn = &pTSchema->columns[iCol];
+ uint8_t flags = pRow->flags & (uint8_t)0xf;
+ SValue value;
+
+ ASSERT(iCol < pTSchema->numOfCols);
+ ASSERT(flags);
+ ASSERT(pRow->sver == pTSchema->version);
+
+ if (iCol == 0) {
+ value.ts = pRow->ts;
+ goto _return_value;
+ }
+
+ if (flags == TSROW_HAS_NONE) {
+ goto _return_none;
+ } else if (flags == TSROW_HAS_NONE) {
+ goto _return_null;
+ }
+
+ ASSERT(pRow->nData && pRow->pData);
+
+ if (isTuple) {
+ uint8_t *pb = pRow->pData;
+ uint8_t *pf = NULL;
+ uint8_t *pv = NULL;
+ uint8_t *p;
+ uint8_t b;
+
+ // bit
+ switch (flags) {
+ case TSROW_HAS_VAL:
+ pf = pb;
+ break;
+ case TSROW_HAS_NULL | TSROW_HAS_NONE:
+ b = GET_BIT1(pb, iCol - 1);
+ if (b == 0) {
+ goto _return_none;
+ } else {
+ goto _return_null;
+ }
+ case TSROW_HAS_VAL | TSROW_HAS_NONE:
+ b = GET_BIT1(pb, iCol - 1);
+ if (b == 0) {
+ goto _return_none;
+ } else {
+ pf = pb + BIT1_SIZE(pTSchema->numOfCols - 1);
+ break;
+ }
+ case TSROW_HAS_VAL | TSROW_HAS_NULL:
+ b = GET_BIT1(pb, iCol - 1);
+ if (b == 0) {
+ goto _return_null;
+ } else {
+ pf = pb + BIT1_SIZE(pTSchema->numOfCols - 1);
+ break;
+ }
+ case TSROW_HAS_VAL | TSROW_HAS_NULL | TSROW_HAS_NONE:
+ b = GET_BIT2(pb, iCol - 1);
+ if (b == 0) {
+ goto _return_none;
+ } else if (b == 1) {
+ goto _return_null;
+ } else {
+ pf = pb + BIT2_SIZE(pTSchema->numOfCols - 1);
+ break;
+ }
+ default:
+ ASSERT(0);
+ }
+
+ ASSERT(pf);
+
+ p = pf + pTColumn->offset;
+ if (IS_VAR_DATA_TYPE(pTColumn->type)) {
+ pv = pf + pTSchema->flen;
+ p = pv + *(VarDataOffsetT *)p;
+ }
+ tGetValue(p, &value, pTColumn->type);
+ goto _return_value;
+ } else {
+ STSKVRow *pRowK = (STSKVRow *)pRow->pData;
+ int16_t lidx = 0;
+ int16_t ridx = pRowK->nCols - 1;
+ uint8_t *p;
+ int16_t midx;
+ uint32_t n;
+ int16_t cid;
+
+ ASSERT(pRowK->nCols > 0);
+
+ if (pRow->flags & TSROW_KV_SMALL) {
+ p = pRow->pData + sizeof(STSKVRow) + sizeof(uint8_t) * pRowK->nCols;
+ } else if (pRow->flags & TSROW_KV_MID) {
+ p = pRow->pData + sizeof(STSKVRow) + sizeof(uint16_t) * pRowK->nCols;
+ } else if (pRow->flags & TSROW_KV_BIG) {
+ p = pRow->pData + sizeof(STSKVRow) + sizeof(uint32_t) * pRowK->nCols;
+ } else {
+ ASSERT(0);
+ }
+ while (lidx <= ridx) {
+ midx = (lidx + ridx) / 2;
+
+ if (pRow->flags & TSROW_KV_SMALL) {
+ n = ((uint8_t *)pRowK->idx)[midx];
+ } else if (pRow->flags & TSROW_KV_MID) {
+ n = ((uint16_t *)pRowK->idx)[midx];
+ } else {
+ n = ((uint32_t *)pRowK->idx)[midx];
+ }
+
+ n += tGetI16v(p + n, &cid);
+
+ if (TABS(cid) == pTColumn->colId) {
+ if (cid < 0) {
+ goto _return_null;
+ } else {
+ n += tGetValue(p + n, &value, pTColumn->type);
+ goto _return_value;
+ }
+
+ return;
+ } else if (TABS(cid) > pTColumn->colId) {
+ ridx = midx - 1;
+ } else {
+ lidx = midx + 1;
+ }
+ }
+
+ // not found, return NONE
+ goto _return_none;
+ }
+
+_return_none:
+ *pColVal = COL_VAL_NONE(pTColumn->colId);
+ return;
+
+_return_null:
+ *pColVal = COL_VAL_NULL(pTColumn->colId);
+ return;
+
+_return_value:
+ *pColVal = COL_VAL_VALUE(pTColumn->colId, value);
+ return;
+}
+
+int32_t tTSRowToArray(STSRow2 *pRow, STSchema *pTSchema, SArray **ppArray) {
+ int32_t code = 0;
+ SColVal cv;
+
+ (*ppArray) = taosArrayInit(pTSchema->numOfCols, sizeof(SColVal));
+ if (*ppArray == NULL) {
+ code = TSDB_CODE_OUT_OF_MEMORY;
+ goto _exit;
+ }
+
+ for (int32_t iColumn = 0; iColumn < pTSchema->numOfCols; iColumn++) {
+ tTSRowGet(pRow, pTSchema, iColumn, &cv);
+ taosArrayPush(*ppArray, &cv);
+ }
+
+_exit:
+ return code;
+}
+
int32_t tPutTSRow(uint8_t *p, STSRow2 *pRow) {
int32_t n = 0;
@@ -67,8 +551,11 @@ int32_t tPutTSRow(uint8_t *p, STSRow2 *pRow) {
switch (pRow->flags & 0xf) {
case TSROW_HAS_NONE:
case TSROW_HAS_NULL:
+ ASSERT(pRow->nData == 0);
+ ASSERT(pRow->pData == NULL);
break;
default:
+ ASSERT(pRow->nData && pRow->pData);
n += tPutBinary(p ? p + n : p, pRow->pData, pRow->nData);
break;
}
@@ -78,149 +565,26 @@ int32_t tPutTSRow(uint8_t *p, STSRow2 *pRow) {
int32_t tGetTSRow(uint8_t *p, STSRow2 *pRow) {
int32_t n = 0;
- uint8_t flags;
- n += tGetI64(p + n, pRow ? &pRow->ts : NULL);
- n += tGetI8(p + n, pRow ? &pRow->flags : &flags);
- n += tGetI32v(p + n, pRow ? &pRow->sver : NULL);
+ n += tGetI64(p + n, &pRow->ts);
+ n += tGetI8(p + n, &pRow->flags);
+ n += tGetI32v(p + n, &pRow->sver);
- if (pRow) flags = pRow->flags;
- switch (flags & 0xf) {
+ ASSERT(pRow->flags);
+ switch (pRow->flags & 0xf) {
case TSROW_HAS_NONE:
case TSROW_HAS_NULL:
+ pRow->nData = 0;
+ pRow->pData = NULL;
break;
default:
- n += tGetBinary(p + n, pRow ? &pRow->pData : NULL, pRow ? &pRow->nData : NULL);
+ n += tGetBinary(p + n, &pRow->pData, &pRow->nData);
break;
}
return n;
}
-int32_t tTSRowDup(const STSRow2 *pRow, STSRow2 **ppRow) {
- (*ppRow) = taosMemoryMalloc(sizeof(*pRow) + pRow->nData);
- if (*ppRow == NULL) {
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- return -1;
- }
-
- (*ppRow)->ts = pRow->ts;
- (*ppRow)->flags = pRow->flags;
- (*ppRow)->sver = pRow->sver;
- (*ppRow)->nData = pRow->nData;
- if (pRow->nData) {
- (*ppRow)->pData = (uint8_t *)(&(*ppRow)[1]);
- memcpy((*ppRow)->pData, pRow->pData, pRow->nData);
- } else {
- (*ppRow)->pData = NULL;
- }
-
- return 0;
-}
-
-void tTSRowFree(STSRow2 *pRow) {
- if (pRow) taosMemoryFree(pRow);
-}
-
-int32_t tTSRowGet(const STSRow2 *pRow, STSchema *pTSchema, int32_t iCol, SColVal *pColVal) {
- uint32_t n;
- uint8_t *p;
- uint8_t v;
- int32_t bidx = iCol - 1;
- STColumn *pTColumn = &pTSchema->columns[iCol];
- STSKVRow *pTSKVRow;
- SKVIdx *pKVIdx;
-
- ASSERT(iCol != 0);
- ASSERT(pTColumn->colId != 0);
-
- ASSERT(pRow->flags & 0xf != 0);
- switch (pRow->flags & 0xf) {
- case TSROW_HAS_NONE:
- *pColVal = ColValNONE;
- return 0;
- case TSROW_HAS_NULL:
- *pColVal = ColValNULL;
- return 0;
- }
-
- if (TSROW_IS_KV_ROW(pRow)) {
- ASSERT((pRow->flags & 0xf) != TSROW_HAS_VAL);
-
- pTSKVRow = (STSKVRow *)pRow->pData;
- pKVIdx =
- bsearch(&((SKVIdx){.cid = pTColumn->colId}), pTSKVRow->idx, pTSKVRow->nCols, sizeof(SKVIdx), tSKVIdxCmprFn);
- if (pKVIdx == NULL) {
- *pColVal = ColValNONE;
- } else if (pKVIdx->offset < 0) {
- *pColVal = ColValNULL;
- } else {
- p = pRow->pData + sizeof(STSKVRow) + sizeof(SKVIdx) * pTSKVRow->nCols + pKVIdx->offset;
- pColVal->type = COL_VAL_DATA;
- tGetBinary(p, &pColVal->pData, &pColVal->nData);
- }
- } else {
- // get bitmap
- p = pRow->pData;
- switch (pRow->flags & 0xf) {
- case TSROW_HAS_NULL | TSROW_HAS_NONE:
- v = GET_BIT1(p, bidx);
- if (v == 0) {
- *pColVal = ColValNONE;
- } else {
- *pColVal = ColValNULL;
- }
- return 0;
- case TSROW_HAS_VAL | TSROW_HAS_NONE:
- v = GET_BIT1(p, bidx);
- if (v == 1) {
- p = p + BIT1_SIZE(pTSchema->numOfCols - 1);
- break;
- } else {
- *pColVal = ColValNONE;
- return 0;
- }
- case TSROW_HAS_VAL | TSROW_HAS_NULL:
- v = GET_BIT1(p, bidx);
- if (v == 1) {
- p = p + BIT1_SIZE(pTSchema->numOfCols - 1);
- break;
- } else {
- *pColVal = ColValNULL;
- return 0;
- }
- case TSROW_HAS_VAL | TSROW_HAS_NULL | TSROW_HAS_NONE:
- v = GET_BIT2(p, bidx);
- if (v == 0) {
- *pColVal = ColValNONE;
- return 0;
- } else if (v == 1) {
- *pColVal = ColValNULL;
- return 0;
- } else if (v == 2) {
- p = p + BIT2_SIZE(pTSchema->numOfCols - 1);
- break;
- } else {
- ASSERT(0);
- }
- default:
- break;
- }
-
- // get real value
- p = p + pTColumn->offset;
- pColVal->type = COL_VAL_DATA;
- if (IS_VAR_DATA_TYPE(pTColumn->type)) {
- tGetBinary(p + pTSchema->flen + *(int32_t *)p, &pColVal->pData, &pColVal->nData);
- } else {
- pColVal->pData = p;
- pColVal->nData = pTColumn->bytes;
- }
- }
-
- return 0;
-}
-
// STSchema
int32_t tTSchemaCreate(int32_t sver, SSchema *pSchema, int32_t ncols, STSchema **ppTSchema) {
*ppTSchema = (STSchema *)taosMemoryMalloc(sizeof(STSchema) + sizeof(STColumn) * ncols);
@@ -262,6 +626,7 @@ void tTSchemaDestroy(STSchema *pTSchema) {
}
// STSRowBuilder
+#if 0
int32_t tTSRowBuilderInit(STSRowBuilder *pBuilder, int32_t sver, int32_t nCols, SSchema *pSchema) {
if (tTSchemaCreate(sver, pSchema, nCols, &pBuilder->pTSchema) < 0) return -1;
@@ -443,7 +808,6 @@ static void setBitMap(uint8_t *p, STSchema *pTSchema, uint8_t flags) {
}
int32_t tTSRowBuilderGetRow(STSRowBuilder *pBuilder, const STSRow2 **ppRow) {
int32_t nDataTP, nDataKV;
- uint32_t flags;
STSKVRow *pTSKVRow = (STSKVRow *)pBuilder->pKVBuf;
int32_t nCols = pBuilder->pTSchema->numOfCols;
@@ -457,7 +821,7 @@ int32_t tTSRowBuilderGetRow(STSRowBuilder *pBuilder, const STSRow2 **ppRow) {
pBuilder->row.flags |= TSROW_HAS_NONE;
}
- ASSERT(pBuilder->row.flags & 0xf != 0);
+ ASSERT((pBuilder->row.flags & 0xf) != 0);
*(ppRow) = &pBuilder->row;
switch (pBuilder->row.flags & 0xf) {
case TSROW_HAS_NONE:
@@ -487,7 +851,7 @@ int32_t tTSRowBuilderGetRow(STSRowBuilder *pBuilder, const STSRow2 **ppRow) {
if (nDataKV < nDataTP) {
// generate KV row
- ASSERT(pBuilder->row.flags & 0xf != TSROW_HAS_VAL);
+ ASSERT((pBuilder->row.flags & 0xf) != TSROW_HAS_VAL);
pBuilder->row.flags |= TSROW_KV_ROW;
pBuilder->row.nData = nDataKV;
@@ -503,12 +867,12 @@ int32_t tTSRowBuilderGetRow(STSRowBuilder *pBuilder, const STSRow2 **ppRow) {
pBuilder->row.nData = nDataTP;
uint8_t *p;
- uint8_t flags = pBuilder->row.flags & 0xf;
+ uint8_t flags = (pBuilder->row.flags & 0xf);
if (flags == TSROW_HAS_VAL) {
pBuilder->row.pData = pBuilder->pTPBuf + pBuilder->szBitMap2;
} else {
- if (flags == TSROW_HAS_VAL | TSROW_HAS_NULL | TSROW_HAS_NONE) {
+ if (flags == (TSROW_HAS_VAL | TSROW_HAS_NULL | TSROW_HAS_NONE)) {
pBuilder->row.pData = pBuilder->pTPBuf;
} else {
pBuilder->row.pData = pBuilder->pTPBuf + pBuilder->szBitMap2 - pBuilder->szBitMap1;
@@ -520,133 +884,375 @@ int32_t tTSRowBuilderGetRow(STSRowBuilder *pBuilder, const STSRow2 **ppRow) {
return 0;
}
+#endif
-static FORCE_INLINE int tTagIdxCmprFn(const void *p1, const void *p2) {
- STagIdx *pTagIdx1 = (STagIdx *)p1;
- STagIdx *pTagIdx2 = (STagIdx *)p2;
- if (pTagIdx1->cid < pTagIdx1->cid) {
+static int tTagValCmprFn(const void *p1, const void *p2) {
+ if (((STagVal *)p1)->cid < ((STagVal *)p2)->cid) {
return -1;
- } else if (pTagIdx1->cid > pTagIdx1->cid) {
+ } else if (((STagVal *)p1)->cid > ((STagVal *)p2)->cid) {
return 1;
}
+
return 0;
}
-int32_t tTagNew(STagVal *pTagVals, int16_t nTag, STag **ppTag) {
- STagVal *pTagVal;
- uint8_t *p;
- int32_t n;
- uint16_t tsize = sizeof(STag) + sizeof(STagIdx) * nTag;
+static int tTagValJsonCmprFn(const void *p1, const void *p2) {
+ return strcmp(((STagVal *)p1)[0].pKey, ((STagVal *)p2)[0].pKey);
+}
- for (int16_t iTag = 0; iTag < nTag; iTag++) {
- pTagVal = &pTagVals[iTag];
+static void debugPrintTagVal(int8_t type, const void *val, int32_t vlen, const char *tag, int32_t ln) {
+ switch (type) {
+ case TSDB_DATA_TYPE_JSON:
+ case TSDB_DATA_TYPE_VARCHAR:
+ case TSDB_DATA_TYPE_NCHAR: {
+ char tmpVal[32] = {0};
+ strncpy(tmpVal, val, vlen > 31 ? 31 : vlen);
+ printf("%s:%d type:%d vlen:%d, val:\"%s\"\n", tag, ln, (int32_t)type, vlen, tmpVal);
+ } break;
+ case TSDB_DATA_TYPE_FLOAT:
+ printf("%s:%d type:%d vlen:%d, val:%f\n", tag, ln, (int32_t)type, vlen, *(float *)val);
+ break;
+ case TSDB_DATA_TYPE_DOUBLE:
+ printf("%s:%d type:%d vlen:%d, val:%lf\n", tag, ln, (int32_t)type, vlen, *(double *)val);
+ break;
+ case TSDB_DATA_TYPE_BOOL:
+ printf("%s:%d type:%d vlen:%d, val:%" PRIu8 "\n", tag, ln, (int32_t)type, vlen, *(uint8_t *)val);
+ break;
+ case TSDB_DATA_TYPE_TINYINT:
+ printf("%s:%d type:%d vlen:%d, val:%" PRIi8 "\n", tag, ln, (int32_t)type, vlen, *(int8_t *)val);
+ break;
+ case TSDB_DATA_TYPE_SMALLINT:
+ printf("%s:%d type:%d vlen:%d, val:%" PRIi16 "\n", tag, ln, (int32_t)type, vlen, *(int16_t *)val);
+ break;
+ case TSDB_DATA_TYPE_INT:
+ printf("%s:%d type:%d vlen:%d, val:%" PRIi32 "\n", tag, ln, (int32_t)type, vlen, *(int32_t *)val);
+ break;
+ case TSDB_DATA_TYPE_BIGINT:
+ printf("%s:%d type:%d vlen:%d, val:%" PRIi64 "\n", tag, ln, (int32_t)type, vlen, *(int64_t *)val);
+ break;
+ case TSDB_DATA_TYPE_TIMESTAMP:
+ printf("%s:%d type:%d vlen:%d, val:%" PRIi64 "\n", tag, ln, (int32_t)type, vlen, *(int64_t *)val);
+ break;
+ case TSDB_DATA_TYPE_UTINYINT:
+ printf("%s:%d type:%d vlen:%d, val:%" PRIu8 "\n", tag, ln, (int32_t)type, vlen, *(uint8_t *)val);
+ break;
+ case TSDB_DATA_TYPE_USMALLINT:
+ printf("%s:%d type:%d vlen:%d, val:%" PRIu16 "\n", tag, ln, (int32_t)type, vlen, *(uint16_t *)val);
+ break;
+ case TSDB_DATA_TYPE_UINT:
+ printf("%s:%d type:%d vlen:%d, val:%" PRIu32 "\n", tag, ln, (int32_t)type, vlen, *(uint32_t *)val);
+ break;
+ case TSDB_DATA_TYPE_UBIGINT:
+ printf("%s:%d type:%d vlen:%d, val:%" PRIu64 "\n", tag, ln, (int32_t)type, vlen, *(uint64_t *)val);
+ break;
+ case TSDB_DATA_TYPE_NULL:
+ printf("%s:%d type:%d vlen:%d, val:%" PRIi8 "\n", tag, ln, (int32_t)type, vlen, *(int8_t *)val);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
- if (IS_VAR_DATA_TYPE(pTagVal->type)) {
- tsize += tPutBinary(NULL, pTagVal->pData, pTagVal->nData);
+// if (isLarge) {
+// p = (uint8_t *)&((int16_t *)pTag->idx)[pTag->nTag];
+// } else {
+// p = (uint8_t *)&pTag->idx[pTag->nTag];
+// }
+
+// (*ppArray) = taosArrayInit(pTag->nTag + 1, sizeof(STagVal));
+// if (*ppArray == NULL) {
+// code = TSDB_CODE_OUT_OF_MEMORY;
+// goto _err;
+// }
+
+// for (int16_t iTag = 0; iTag < pTag->nTag; iTag++) {
+// if (isLarge) {
+// offset = ((int16_t *)pTag->idx)[iTag];
+// } else {
+// offset = pTag->idx[iTag];
+// }
+
+void debugPrintSTag(STag *pTag, const char *tag, int32_t ln) {
+ int8_t isJson = pTag->flags & TD_TAG_JSON;
+ int8_t isLarge = pTag->flags & TD_TAG_LARGE;
+ uint8_t *p = NULL;
+ int16_t offset = 0;
+
+ if (isLarge) {
+ p = (uint8_t *)&((int16_t *)pTag->idx)[pTag->nTag];
+ } else {
+ p = (uint8_t *)&pTag->idx[pTag->nTag];
+ }
+ printf("%s:%d >>> STAG === %s:%s, len: %d, nTag: %d, sver:%d\n", tag, ln, isJson ? "json" : "normal",
+ isLarge ? "large" : "small", (int32_t)pTag->len, (int32_t)pTag->nTag, pTag->ver);
+ for (uint16_t n = 0; n < pTag->nTag; ++n) {
+ if (isLarge) {
+ offset = ((int16_t *)pTag->idx)[n];
} else {
- ASSERT(pTagVal->nData == TYPE_BYTES[pTagVal->type]);
- tsize += pTagVal->nData;
+ offset = pTag->idx[n];
+ }
+ STagVal tagVal = {0};
+ if (isJson) {
+ tagVal.pKey = (char *)POINTER_SHIFT(p, offset);
+ } else {
+ tagVal.cid = *(int16_t *)POINTER_SHIFT(p, offset);
+ }
+ printf("%s:%d loop[%d-%d] offset=%d\n", __func__, __LINE__, (int32_t)pTag->nTag, (int32_t)n, (int32_t)offset);
+ tGetTagVal(p + offset, &tagVal, isJson);
+ if (IS_VAR_DATA_TYPE(tagVal.type)) {
+ debugPrintTagVal(tagVal.type, tagVal.pData, tagVal.nData, __func__, __LINE__);
+ } else {
+ debugPrintTagVal(tagVal.type, &tagVal.i64, tDataTypes[tagVal.type].bytes, __func__, __LINE__);
}
}
+ printf("\n");
+}
- (*ppTag) = (STag *)taosMemoryMalloc(tsize);
- if (*ppTag == NULL) {
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- return -1;
+void debugCheckTags(STag *pTag) {
+ switch (pTag->flags) {
+ case 0x0:
+ case 0x20:
+ case 0x40:
+ case 0x60:
+ break;
+ default:
+ ASSERT(0);
}
- p = (uint8_t *)&((*ppTag)->idx[nTag]);
- n = 0;
+ ASSERT(pTag->nTag <= 128 && pTag->nTag >= 0);
+ ASSERT(pTag->ver <= 512 && pTag->ver >= 0); // temp condition for pTag->ver
+}
- (*ppTag)->len = tsize;
+static int32_t tPutTagVal(uint8_t *p, STagVal *pTagVal, int8_t isJson) {
+ int32_t n = 0;
+
+ // key
+ if (isJson) {
+ n += tPutCStr(p ? p + n : p, pTagVal->pKey);
+ } else {
+ n += tPutI16v(p ? p + n : p, pTagVal->cid);
+ }
+
+ // type
+ n += tPutI8(p ? p + n : p, pTagVal->type);
+
+ // value
+ if (IS_VAR_DATA_TYPE(pTagVal->type)) {
+ n += tPutBinary(p ? p + n : p, pTagVal->pData, pTagVal->nData);
+ } else {
+ p = p ? p + n : p;
+ n += tDataTypes[pTagVal->type].bytes;
+ if (p) memcpy(p, &(pTagVal->i64), tDataTypes[pTagVal->type].bytes);
+ }
+
+ return n;
+}
+static int32_t tGetTagVal(uint8_t *p, STagVal *pTagVal, int8_t isJson) {
+ int32_t n = 0;
+
+ // key
+ if (isJson) {
+ n += tGetCStr(p + n, &pTagVal->pKey);
+ } else {
+ n += tGetI16v(p + n, &pTagVal->cid);
+ }
+
+ // type
+ n += tGetI8(p + n, &pTagVal->type);
+
+ // value
+ if (IS_VAR_DATA_TYPE(pTagVal->type)) {
+ n += tGetBinary(p + n, &pTagVal->pData, &pTagVal->nData);
+ } else {
+ memcpy(&(pTagVal->i64), p + n, tDataTypes[pTagVal->type].bytes);
+ n += tDataTypes[pTagVal->type].bytes;
+ }
+
+ return n;
+}
+int32_t tTagNew(SArray *pArray, int32_t version, int8_t isJson, STag **ppTag) {
+ int32_t code = 0;
+ uint8_t *p = NULL;
+ int16_t n = 0;
+ int16_t nTag = taosArrayGetSize(pArray);
+ int32_t szTag = 0;
+ int8_t isLarge = 0;
+
+ // sort
+ if (isJson) {
+ qsort(pArray->pData, nTag, sizeof(STagVal), tTagValJsonCmprFn);
+ } else {
+ qsort(pArray->pData, nTag, sizeof(STagVal), tTagValCmprFn);
+ }
+
+ // get size
+ for (int16_t iTag = 0; iTag < nTag; iTag++) {
+ szTag += tPutTagVal(NULL, (STagVal *)taosArrayGet(pArray, iTag), isJson);
+ }
+ if (szTag <= INT8_MAX) {
+ szTag = szTag + sizeof(STag) + sizeof(int8_t) * nTag;
+ } else {
+ szTag = szTag + sizeof(STag) + sizeof(int16_t) * nTag;
+ isLarge = 1;
+ }
+
+ ASSERT(szTag <= INT16_MAX);
+
+ // build tag
+ (*ppTag) = (STag *)taosMemoryCalloc(szTag, 1);
+ if ((*ppTag) == NULL) {
+ code = TSDB_CODE_OUT_OF_MEMORY;
+ goto _err;
+ }
+ (*ppTag)->flags = 0;
+ if (isJson) {
+ (*ppTag)->flags |= TD_TAG_JSON;
+ }
+ if (isLarge) {
+ (*ppTag)->flags |= TD_TAG_LARGE;
+ }
+ (*ppTag)->len = szTag;
(*ppTag)->nTag = nTag;
- for (int16_t iTag = 0; iTag < nTag; iTag++) {
- pTagVal = &pTagVals[iTag];
+ (*ppTag)->ver = version;
- (*ppTag)->idx[iTag].cid = pTagVal->cid;
- (*ppTag)->idx[iTag].offset = n;
-
- if (IS_VAR_DATA_TYPE(pTagVal->type)) {
- n += tPutBinary(p + n, pTagVal->pData, pTagVal->nData);
- } else {
- memcpy(p + n, pTagVal->pData, pTagVal->nData);
- n += pTagVal->nData;
- }
+ if (isLarge) {
+ p = (uint8_t *)&((int16_t *)(*ppTag)->idx)[nTag];
+ } else {
+ p = (uint8_t *)&(*ppTag)->idx[nTag];
}
+ n = 0;
+ for (int16_t iTag = 0; iTag < nTag; iTag++) {
+ if (isLarge) {
+ ((int16_t *)(*ppTag)->idx)[iTag] = n;
+ } else {
+ (*ppTag)->idx[iTag] = n;
+ }
+ n += tPutTagVal(p + n, (STagVal *)taosArrayGet(pArray, iTag), isJson);
+ }
+#ifdef TD_DEBUG_PRINT_TAG
+ debugPrintSTag(*ppTag, __func__, __LINE__);
+#endif
- qsort((*ppTag)->idx, (*ppTag)->nTag, sizeof(STagIdx), tTagIdxCmprFn);
- return 0;
+ debugCheckTags(*ppTag); // TODO: remove this line after debug
+ return code;
+
+_err:
+ return code;
}
void tTagFree(STag *pTag) {
if (pTag) taosMemoryFree(pTag);
}
-int32_t tTagSet(STag *pTag, SSchema *pSchema, int32_t nCols, int iCol, uint8_t *pData, uint32_t nData, STag **ppTag) {
- STagVal *pTagVals;
- int16_t nTags = 0;
- SSchema *pColumn;
- uint8_t *p;
- uint32_t n;
-
- pTagVals = (STagVal *)taosMemoryMalloc(sizeof(*pTagVals) * nCols);
- if (pTagVals == NULL) {
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- return -1;
+char *tTagValToData(const STagVal *value, bool isJson) {
+ if (!value) return NULL;
+ char *data = NULL;
+ int8_t typeBytes = 0;
+ if (isJson) {
+ typeBytes = CHAR_BYTES;
+ }
+ if (IS_VAR_DATA_TYPE(value->type)) {
+ data = taosMemoryCalloc(1, typeBytes + VARSTR_HEADER_SIZE + value->nData);
+ if (data == NULL) return NULL;
+ if (isJson) *data = value->type;
+ varDataLen(data + typeBytes) = value->nData;
+ memcpy(varDataVal(data + typeBytes), value->pData, value->nData);
+ } else {
+ data = ((char *)&(value->i64)) - typeBytes; // json with type
}
- for (int32_t i = 0; i < nCols; i++) {
- pColumn = &pSchema[i];
-
- if (i == iCol) {
- p = pData;
- n = nData;
- } else {
- tTagGet(pTag, pColumn->colId, pColumn->type, &p, &n);
- }
-
- if (p == NULL) continue;
-
- ASSERT(IS_VAR_DATA_TYPE(pColumn->type) || n == pColumn->bytes);
-
- pTagVals[nTags].cid = pColumn->colId;
- pTagVals[nTags].type = pColumn->type;
- pTagVals[nTags].nData = n;
- pTagVals[nTags].pData = p;
-
- nTags++;
- }
-
- // create new tag
- if (tTagNew(pTagVals, nTags, ppTag) < 0) {
- taosMemoryFree(pTagVals);
- return -1;
- }
-
- taosMemoryFree(pTagVals);
- return 0;
+ return data;
}
-void tTagGet(STag *pTag, int16_t cid, int8_t type, uint8_t **ppData, uint32_t *nData) {
- STagIdx *pTagIdx = bsearch(&((STagIdx){.cid = cid}), pTag->idx, pTag->nTag, sizeof(STagIdx), tTagIdxCmprFn);
- if (pTagIdx == NULL) {
- *ppData = NULL;
- *nData = 0;
+bool tTagGet(const STag *pTag, STagVal *pTagVal) {
+ int16_t lidx = 0;
+ int16_t ridx = pTag->nTag - 1;
+ int16_t midx;
+ uint8_t *p;
+ int8_t isJson = pTag->flags & TD_TAG_JSON;
+ int8_t isLarge = pTag->flags & TD_TAG_LARGE;
+ int16_t offset;
+ STagVal tv;
+ int c;
+
+ if (isLarge) {
+ p = (uint8_t *)&((int16_t *)pTag->idx)[pTag->nTag];
} else {
- uint8_t *p = (uint8_t *)&pTag->idx[pTag->nTag] + pTagIdx->offset;
- if (IS_VAR_DATA_TYPE(type)) {
- tGetBinary(p, ppData, nData);
+ p = (uint8_t *)&pTag->idx[pTag->nTag];
+ }
+
+ pTagVal->type = TSDB_DATA_TYPE_NULL;
+ pTagVal->pData = NULL;
+ pTagVal->nData = 0;
+ while (lidx <= ridx) {
+ midx = (lidx + ridx) / 2;
+ if (isLarge) {
+ offset = ((int16_t *)pTag->idx)[midx];
} else {
- *ppData = p;
- *nData = TYPE_BYTES[type];
+ offset = pTag->idx[midx];
+ }
+
+ tGetTagVal(p + offset, &tv, isJson);
+ if (isJson) {
+ c = tTagValJsonCmprFn(pTagVal, &tv);
+ } else {
+ c = tTagValCmprFn(pTagVal, &tv);
+ }
+
+ if (c < 0) {
+ ridx = midx - 1;
+ } else if (c > 0) {
+ lidx = midx + 1;
+ } else {
+ memcpy(pTagVal, &tv, sizeof(tv));
+ return true;
}
}
+ return false;
}
int32_t tEncodeTag(SEncoder *pEncoder, const STag *pTag) {
return tEncodeBinary(pEncoder, (const uint8_t *)pTag, pTag->len);
}
-int32_t tDecodeTag(SDecoder *pDecoder, STag **ppTag) { return tDecodeBinary(pDecoder, (uint8_t **)ppTag, NULL); }
+int32_t tDecodeTag(SDecoder *pDecoder, STag **ppTag) {
+ return tDecodeBinary(pDecoder, (uint8_t **)ppTag, NULL);
+}
+
+int32_t tTagToValArray(const STag *pTag, SArray **ppArray) {
+ int32_t code = 0;
+ uint8_t *p = NULL;
+ STagVal tv = {0};
+ int8_t isLarge = pTag->flags & TD_TAG_LARGE;
+ int16_t offset = 0;
+
+ if (isLarge) {
+ p = (uint8_t *)&((int16_t *)pTag->idx)[pTag->nTag];
+ } else {
+ p = (uint8_t *)&pTag->idx[pTag->nTag];
+ }
+
+ (*ppArray) = taosArrayInit(pTag->nTag + 1, sizeof(STagVal));
+ if (*ppArray == NULL) {
+ code = TSDB_CODE_OUT_OF_MEMORY;
+ goto _err;
+ }
+
+ for (int16_t iTag = 0; iTag < pTag->nTag; iTag++) {
+ if (isLarge) {
+ offset = ((int16_t *)pTag->idx)[iTag];
+ } else {
+ offset = pTag->idx[iTag];
+ }
+ tGetTagVal(p + offset, &tv, pTag->flags & TD_TAG_JSON);
+ taosArrayPush(*ppArray, &tv);
+ }
+
+ return code;
+
+_err:
+ return code;
+}
#if 1 // ===================================================================================================================
static void dataColSetNEleNull(SDataCol *pCol, int nEle);
@@ -974,162 +1580,4 @@ void tdResetDataCols(SDataCols *pCols) {
}
}
-SKVRow tdKVRowDup(SKVRow row) {
- SKVRow trow = taosMemoryMalloc(kvRowLen(row));
- if (trow == NULL) return NULL;
-
- kvRowCpy(trow, row);
- return trow;
-}
-
-static int compareColIdx(const void *a, const void *b) {
- const SColIdx *x = (const SColIdx *)a;
- const SColIdx *y = (const SColIdx *)b;
- if (x->colId > y->colId) {
- return 1;
- }
- if (x->colId < y->colId) {
- return -1;
- }
- return 0;
-}
-
-void tdSortKVRowByColIdx(SKVRow row) { qsort(kvRowColIdx(row), kvRowNCols(row), sizeof(SColIdx), compareColIdx); }
-
-int tdSetKVRowDataOfCol(SKVRow *orow, int16_t colId, int8_t type, void *value) {
- SColIdx *pColIdx = NULL;
- SKVRow row = *orow;
- SKVRow nrow = NULL;
- void *ptr = taosbsearch(&colId, kvRowColIdx(row), kvRowNCols(row), sizeof(SColIdx), comparTagId, TD_GE);
-
- if (ptr == NULL || ((SColIdx *)ptr)->colId > colId) { // need to add a column value to the row
- int diff = IS_VAR_DATA_TYPE(type) ? varDataTLen(value) : TYPE_BYTES[type];
- int nRowLen = kvRowLen(row) + sizeof(SColIdx) + diff;
- int oRowCols = kvRowNCols(row);
-
- ASSERT(diff > 0);
- nrow = taosMemoryMalloc(nRowLen);
- if (nrow == NULL) return -1;
-
- kvRowSetLen(nrow, nRowLen);
- kvRowSetNCols(nrow, oRowCols + 1);
-
- memcpy(kvRowColIdx(nrow), kvRowColIdx(row), sizeof(SColIdx) * oRowCols);
- memcpy(kvRowValues(nrow), kvRowValues(row), kvRowValLen(row));
-
- pColIdx = kvRowColIdxAt(nrow, oRowCols);
- pColIdx->colId = colId;
- pColIdx->offset = kvRowValLen(row);
-
- memcpy(kvRowColVal(nrow, pColIdx), value, diff); // copy new value
-
- tdSortKVRowByColIdx(nrow);
-
- *orow = nrow;
- taosMemoryFree(row);
- } else {
- ASSERT(((SColIdx *)ptr)->colId == colId);
- if (IS_VAR_DATA_TYPE(type)) {
- void *pOldVal = kvRowColVal(row, (SColIdx *)ptr);
-
- if (varDataTLen(value) == varDataTLen(pOldVal)) { // just update the column value in place
- memcpy(pOldVal, value, varDataTLen(value));
- } else { // need to reallocate the memory
- int16_t nlen = kvRowLen(row) + (varDataTLen(value) - varDataTLen(pOldVal));
- ASSERT(nlen > 0);
- nrow = taosMemoryMalloc(nlen);
- if (nrow == NULL) return -1;
-
- kvRowSetLen(nrow, nlen);
- kvRowSetNCols(nrow, kvRowNCols(row));
-
- int zsize = sizeof(SColIdx) * kvRowNCols(row) + ((SColIdx *)ptr)->offset;
- memcpy(kvRowColIdx(nrow), kvRowColIdx(row), zsize);
- memcpy(kvRowColVal(nrow, ((SColIdx *)ptr)), value, varDataTLen(value));
- // Copy left value part
- int lsize = kvRowLen(row) - TD_KV_ROW_HEAD_SIZE - zsize - varDataTLen(pOldVal);
- if (lsize > 0) {
- memcpy(POINTER_SHIFT(nrow, TD_KV_ROW_HEAD_SIZE + zsize + varDataTLen(value)),
- POINTER_SHIFT(row, TD_KV_ROW_HEAD_SIZE + zsize + varDataTLen(pOldVal)), lsize);
- }
-
- for (int i = 0; i < kvRowNCols(nrow); i++) {
- pColIdx = kvRowColIdxAt(nrow, i);
-
- if (pColIdx->offset > ((SColIdx *)ptr)->offset) {
- pColIdx->offset = pColIdx->offset - varDataTLen(pOldVal) + varDataTLen(value);
- }
- }
-
- *orow = nrow;
- taosMemoryFree(row);
- }
- } else {
- memcpy(kvRowColVal(row, (SColIdx *)ptr), value, TYPE_BYTES[type]);
- }
- }
-
- return 0;
-}
-
-int tdEncodeKVRow(void **buf, SKVRow row) {
- // May change the encode purpose
- if (buf != NULL) {
- kvRowCpy(*buf, row);
- *buf = POINTER_SHIFT(*buf, kvRowLen(row));
- }
-
- return kvRowLen(row);
-}
-
-void *tdDecodeKVRow(void *buf, SKVRow *row) {
- *row = tdKVRowDup(buf);
- if (*row == NULL) return NULL;
- return POINTER_SHIFT(buf, kvRowLen(*row));
-}
-
-int tdInitKVRowBuilder(SKVRowBuilder *pBuilder) {
- pBuilder->tCols = 128;
- pBuilder->nCols = 0;
- pBuilder->pColIdx = (SColIdx *)taosMemoryMalloc(sizeof(SColIdx) * pBuilder->tCols);
- if (pBuilder->pColIdx == NULL) return -1;
- pBuilder->alloc = 1024;
- pBuilder->size = 0;
- pBuilder->buf = taosMemoryMalloc(pBuilder->alloc);
- if (pBuilder->buf == NULL) {
- taosMemoryFree(pBuilder->pColIdx);
- return -1;
- }
- return 0;
-}
-
-void tdDestroyKVRowBuilder(SKVRowBuilder *pBuilder) {
- taosMemoryFreeClear(pBuilder->pColIdx);
- taosMemoryFreeClear(pBuilder->buf);
-}
-
-void tdResetKVRowBuilder(SKVRowBuilder *pBuilder) {
- pBuilder->nCols = 0;
- pBuilder->size = 0;
-}
-
-SKVRow tdGetKVRowFromBuilder(SKVRowBuilder *pBuilder) {
- int tlen = sizeof(SColIdx) * pBuilder->nCols + pBuilder->size;
- // if (tlen == 0) return NULL; // nCols == 0 means no tags
-
- tlen += TD_KV_ROW_HEAD_SIZE;
-
- SKVRow row = taosMemoryMalloc(tlen);
- if (row == NULL) return NULL;
-
- kvRowSetNCols(row, pBuilder->nCols);
- kvRowSetLen(row, tlen);
-
- if (pBuilder->nCols > 0) {
- memcpy(kvRowColIdx(row), pBuilder->pColIdx, sizeof(SColIdx) * pBuilder->nCols);
- memcpy(kvRowValues(row), pBuilder->buf, pBuilder->size);
- }
-
- return row;
-}
#endif
\ No newline at end of file
diff --git a/source/common/src/tmsg.c b/source/common/src/tmsg.c
index 179631d8c4..0f3eec01c6 100644
--- a/source/common/src/tmsg.c
+++ b/source/common/src/tmsg.c
@@ -28,7 +28,7 @@
#undef TD_MSG_SEG_CODE_
#include "tmsgdef.h"
-int32_t tInitSubmitMsgIter(SSubmitReq *pMsg, SSubmitMsgIter *pIter) {
+int32_t tInitSubmitMsgIter(const SSubmitReq *pMsg, SSubmitMsgIter *pIter) {
if (pMsg == NULL) {
terrno = TSDB_CODE_TDB_SUBMIT_MSG_MSSED_UP;
return -1;
@@ -165,7 +165,6 @@ int32_t tDecodeSQueryNodeLoad(SDecoder *pDecoder, SQueryNodeLoad *pLoad) {
return 0;
}
-
int32_t taosEncodeSEpSet(void **buf, const SEpSet *pEp) {
int32_t tlen = 0;
tlen += taosEncodeFixedI8(buf, pEp->inUse);
@@ -2935,7 +2934,6 @@ int32_t tSerializeSCreateVnodeReq(void *buf, int32_t bufLen, SCreateVnodeReq *pR
if (tStartEncode(&encoder) < 0) return -1;
if (tEncodeI32(&encoder, pReq->vgId) < 0) return -1;
- if (tEncodeI32(&encoder, pReq->dnodeId) < 0) return -1;
if (tEncodeCStr(&encoder, pReq->db) < 0) return -1;
if (tEncodeI64(&encoder, pReq->dbUid) < 0) return -1;
if (tEncodeI32(&encoder, pReq->vgVersion) < 0) return -1;
@@ -2958,6 +2956,7 @@ int32_t tSerializeSCreateVnodeReq(void *buf, int32_t bufLen, SCreateVnodeReq *pR
if (tEncodeI8(&encoder, pReq->compression) < 0) return -1;
if (tEncodeI8(&encoder, pReq->strict) < 0) return -1;
if (tEncodeI8(&encoder, pReq->cacheLastRow) < 0) return -1;
+ if (tEncodeI8(&encoder, pReq->standby) < 0) return -1;
if (tEncodeI8(&encoder, pReq->replica) < 0) return -1;
if (tEncodeI8(&encoder, pReq->selfIndex) < 0) return -1;
for (int32_t i = 0; i < TSDB_MAX_REPLICA; ++i) {
@@ -2992,7 +2991,6 @@ int32_t tDeserializeSCreateVnodeReq(void *buf, int32_t bufLen, SCreateVnodeReq *
if (tStartDecode(&decoder) < 0) return -1;
if (tDecodeI32(&decoder, &pReq->vgId) < 0) return -1;
- if (tDecodeI32(&decoder, &pReq->dnodeId) < 0) return -1;
if (tDecodeCStrTo(&decoder, pReq->db) < 0) return -1;
if (tDecodeI64(&decoder, &pReq->dbUid) < 0) return -1;
if (tDecodeI32(&decoder, &pReq->vgVersion) < 0) return -1;
@@ -3015,6 +3013,7 @@ int32_t tDeserializeSCreateVnodeReq(void *buf, int32_t bufLen, SCreateVnodeReq *
if (tDecodeI8(&decoder, &pReq->compression) < 0) return -1;
if (tDecodeI8(&decoder, &pReq->strict) < 0) return -1;
if (tDecodeI8(&decoder, &pReq->cacheLastRow) < 0) return -1;
+ if (tDecodeI8(&decoder, &pReq->standby) < 0) return -1;
if (tDecodeI8(&decoder, &pReq->replica) < 0) return -1;
if (tDecodeI8(&decoder, &pReq->selfIndex) < 0) return -1;
for (int32_t i = 0; i < TSDB_MAX_REPLICA; ++i) {
@@ -3054,7 +3053,7 @@ int32_t tDeserializeSCreateVnodeReq(void *buf, int32_t bufLen, SCreateVnodeReq *
int32_t tFreeSCreateVnodeReq(SCreateVnodeReq *pReq) {
taosArrayDestroy(pReq->pRetensions);
pReq->pRetensions = NULL;
- if(pReq->isTsma) {
+ if (pReq->isTsma) {
taosMemoryFreeClear(pReq->pTsma);
}
return 0;
@@ -3135,8 +3134,8 @@ int32_t tSerializeSAlterVnodeReq(void *buf, int32_t bufLen, SAlterVnodeReq *pReq
if (tEncodeI8(&encoder, pReq->walLevel) < 0) return -1;
if (tEncodeI8(&encoder, pReq->strict) < 0) return -1;
if (tEncodeI8(&encoder, pReq->cacheLastRow) < 0) return -1;
- if (tEncodeI8(&encoder, pReq->replica) < 0) return -1;
if (tEncodeI8(&encoder, pReq->selfIndex) < 0) return -1;
+ if (tEncodeI8(&encoder, pReq->replica) < 0) return -1;
for (int32_t i = 0; i < TSDB_MAX_REPLICA; ++i) {
SReplica *pReplica = &pReq->replicas[i];
if (tEncodeSReplica(&encoder, pReplica) < 0) return -1;
@@ -3166,8 +3165,8 @@ int32_t tDeserializeSAlterVnodeReq(void *buf, int32_t bufLen, SAlterVnodeReq *pR
if (tDecodeI8(&decoder, &pReq->walLevel) < 0) return -1;
if (tDecodeI8(&decoder, &pReq->strict) < 0) return -1;
if (tDecodeI8(&decoder, &pReq->cacheLastRow) < 0) return -1;
- if (tDecodeI8(&decoder, &pReq->replica) < 0) return -1;
if (tDecodeI8(&decoder, &pReq->selfIndex) < 0) return -1;
+ if (tDecodeI8(&decoder, &pReq->replica) < 0) return -1;
for (int32_t i = 0; i < TSDB_MAX_REPLICA; ++i) {
SReplica *pReplica = &pReq->replicas[i];
if (tDecodeSReplica(&decoder, pReplica) < 0) return -1;
@@ -3655,6 +3654,7 @@ int32_t tEncodeTSma(SEncoder *pCoder, const STSma *pSma) {
if (tEncodeI8(pCoder, pSma->intervalUnit) < 0) return -1;
if (tEncodeI8(pCoder, pSma->slidingUnit) < 0) return -1;
if (tEncodeI8(pCoder, pSma->timezoneInt) < 0) return -1;
+ if (tEncodeI32(pCoder, pSma->dstVgId) < 0) return -1;
if (tEncodeCStr(pCoder, pSma->indexName) < 0) return -1;
if (tEncodeI32(pCoder, pSma->exprLen) < 0) return -1;
if (tEncodeI32(pCoder, pSma->tagsFilterLen) < 0) return -1;
@@ -3677,6 +3677,7 @@ int32_t tDecodeTSma(SDecoder *pCoder, STSma *pSma) {
if (tDecodeI8(pCoder, &pSma->version) < 0) return -1;
if (tDecodeI8(pCoder, &pSma->intervalUnit) < 0) return -1;
if (tDecodeI8(pCoder, &pSma->slidingUnit) < 0) return -1;
+ if (tDecodeI32(pCoder, &pSma->dstVgId) < 0) return -1;
if (tDecodeI8(pCoder, &pSma->timezoneInt) < 0) return -1;
if (tDecodeCStrTo(pCoder, pSma->indexName) < 0) return -1;
if (tDecodeI32(pCoder, &pSma->exprLen) < 0) return -1;
@@ -3910,7 +3911,7 @@ int tEncodeSVCreateTbReq(SEncoder *pCoder, const SVCreateTbReq *pReq) {
if (pReq->type == TSDB_CHILD_TABLE) {
if (tEncodeI64(pCoder, pReq->ctb.suid) < 0) return -1;
- if (tEncodeBinary(pCoder, pReq->ctb.pTag, kvRowLen(pReq->ctb.pTag)) < 0) return -1;
+ if (tEncodeTag(pCoder, (const STag *)pReq->ctb.pTag) < 0) return -1;
} else if (pReq->type == TSDB_NORMAL_TABLE) {
if (tEncodeSSchemaWrapper(pCoder, &pReq->ntb.schemaRow) < 0) return -1;
} else {
@@ -3922,8 +3923,6 @@ int tEncodeSVCreateTbReq(SEncoder *pCoder, const SVCreateTbReq *pReq) {
}
int tDecodeSVCreateTbReq(SDecoder *pCoder, SVCreateTbReq *pReq) {
- uint32_t len;
-
if (tStartDecode(pCoder) < 0) return -1;
if (tDecodeI32v(pCoder, &pReq->flags) < 0) return -1;
@@ -3935,7 +3934,7 @@ int tDecodeSVCreateTbReq(SDecoder *pCoder, SVCreateTbReq *pReq) {
if (pReq->type == TSDB_CHILD_TABLE) {
if (tDecodeI64(pCoder, &pReq->ctb.suid) < 0) return -1;
- if (tDecodeBinary(pCoder, &pReq->ctb.pTag, &len) < 0) return -1;
+ if (tDecodeTag(pCoder, (STag **)&pReq->ctb.pTag) < 0) return -1;
} else if (pReq->type == TSDB_NORMAL_TABLE) {
if (tDecodeSSchemaWrapper(pCoder, &pReq->ntb.schemaRow) < 0) return -1;
} else {
diff --git a/source/dnode/mgmt/mgmt_mnode/src/mmHandle.c b/source/dnode/mgmt/mgmt_mnode/src/mmHandle.c
index 34576d5441..5c5316e3a3 100644
--- a/source/dnode/mgmt/mgmt_mnode/src/mmHandle.c
+++ b/source/dnode/mgmt/mgmt_mnode/src/mmHandle.c
@@ -219,9 +219,9 @@ SArray *mmGetMsgHandles() {
if (dmSetMgmtHandle(pArray, TDMT_VND_DROP_TASK, mmPutNodeMsgToQueryQueue, 1) == NULL) goto _OVER;
if (dmSetMgmtHandle(pArray, TDMT_VND_QUERY_HEARTBEAT, mmPutNodeMsgToQueryQueue, 1) == NULL) goto _OVER;
- if (dmSetMgmtHandle(pArray, TDMT_VND_ALTER_VNODE_RSP, mmPutNodeMsgToWriteQueue, 0) == NULL) goto _OVER;
- if (dmSetMgmtHandle(pArray, TDMT_VND_SYNC_VNODE_RSP, mmPutNodeMsgToWriteQueue, 0) == NULL) goto _OVER;
- if (dmSetMgmtHandle(pArray, TDMT_VND_COMPACT_VNODE_RSP, mmPutNodeMsgToWriteQueue, 0) == NULL) goto _OVER;
+ if (dmSetMgmtHandle(pArray, TDMT_VND_ALTER_CONFIG_RSP, mmPutNodeMsgToWriteQueue, 0) == NULL) goto _OVER;
+ if (dmSetMgmtHandle(pArray, TDMT_VND_ALTER_REPLICA_RSP, mmPutNodeMsgToWriteQueue, 0) == NULL) goto _OVER;
+ if (dmSetMgmtHandle(pArray, TDMT_VND_COMPACT_RSP, mmPutNodeMsgToWriteQueue, 0) == NULL) goto _OVER;
if (dmSetMgmtHandle(pArray, TDMT_VND_SYNC_TIMEOUT, mmPutNodeMsgToSyncQueue, 1) == NULL) goto _OVER;
if (dmSetMgmtHandle(pArray, TDMT_VND_SYNC_PING, mmPutNodeMsgToSyncQueue, 1) == NULL) goto _OVER;
diff --git a/source/dnode/mgmt/mgmt_vnode/src/vmHandle.c b/source/dnode/mgmt/mgmt_vnode/src/vmHandle.c
index 27ea19a5dc..018d7a607c 100644
--- a/source/dnode/mgmt/mgmt_vnode/src/vmHandle.c
+++ b/source/dnode/mgmt/mgmt_vnode/src/vmHandle.c
@@ -150,20 +150,26 @@ static void vmGenerateVnodeCfg(SCreateVnodeReq *pCreate, SVnodeCfg *pCfg) {
pCfg->tsdbCfg.minRows = pCreate->minRows;
pCfg->tsdbCfg.maxRows = pCreate->maxRows;
for (size_t i = 0; i < taosArrayGetSize(pCreate->pRetensions); ++i) {
- memcpy(&pCfg->tsdbCfg.retentions[i], taosArrayGet(pCreate->pRetensions, i), sizeof(SRetention));
+ SRetention *pRetention = &pCfg->tsdbCfg.retentions[i];
+ memcpy(pRetention, taosArrayGet(pCreate->pRetensions, i), sizeof(SRetention));
+ if (i == 0) {
+ if ((pRetention->freq > 0 && pRetention->keep > 0)) pCfg->isRsma = 1;
+ }
}
+
pCfg->walCfg.vgId = pCreate->vgId;
pCfg->hashBegin = pCreate->hashBegin;
pCfg->hashEnd = pCreate->hashEnd;
pCfg->hashMethod = pCreate->hashMethod;
+ pCfg->standby = pCfg->standby;
pCfg->syncCfg.myIndex = pCreate->selfIndex;
pCfg->syncCfg.replicaNum = pCreate->replica;
memset(&pCfg->syncCfg.nodeInfo, 0, sizeof(pCfg->syncCfg.nodeInfo));
for (int i = 0; i < pCreate->replica; ++i) {
- pCfg->syncCfg.nodeInfo[i].nodePort = pCreate->replicas[i].port;
- snprintf(pCfg->syncCfg.nodeInfo[i].nodeFqdn, sizeof(pCfg->syncCfg.nodeInfo[i].nodeFqdn), "%s",
- pCreate->replicas[i].fqdn);
+ SNodeInfo *pNode = &pCfg->syncCfg.nodeInfo[i];
+ pNode->nodePort = pCreate->replicas[i].port;
+ tstrncpy(pNode->nodeFqdn, pCreate->replicas[i].fqdn, sizeof(pNode->nodeFqdn));
}
}
@@ -176,6 +182,8 @@ static void vmGenerateWrapperCfg(SVnodeMgmt *pMgmt, SCreateVnodeReq *pCreate, SW
int32_t vmProcessCreateVnodeReq(SVnodeMgmt *pMgmt, SRpcMsg *pMsg) {
SCreateVnodeReq createReq = {0};
+ SVnodeCfg vnodeCfg = {0};
+ SWrapperCfg wrapperCfg = {0};
int32_t code = -1;
char path[TSDB_FILENAME_LEN] = {0};
@@ -184,12 +192,9 @@ int32_t vmProcessCreateVnodeReq(SVnodeMgmt *pMgmt, SRpcMsg *pMsg) {
return -1;
}
- dDebug("vgId:%d, create vnode req is received, tsma:%d", createReq.vgId, createReq.isTsma);
-
- SVnodeCfg vnodeCfg = {0};
+ dDebug("vgId:%d, create vnode req is received, tsma:%d standby:%d", createReq.vgId, createReq.isTsma,
+ createReq.standby);
vmGenerateVnodeCfg(&createReq, &vnodeCfg);
-
- SWrapperCfg wrapperCfg = {0};
vmGenerateWrapperCfg(pMgmt, &createReq, &wrapperCfg);
SVnodeObj *pVnode = vmAcquireVnode(pMgmt, createReq.vgId);
@@ -218,9 +223,20 @@ int32_t vmProcessCreateVnodeReq(SVnodeMgmt *pMgmt, SRpcMsg *pMsg) {
code = vmOpenVnode(pMgmt, &wrapperCfg, pImpl);
if (code != 0) {
dError("vgId:%d, failed to open vnode since %s", createReq.vgId, terrstr());
+ code = terrno;
goto _OVER;
}
+ if (createReq.isTsma) {
+ SMsgHead *smaMsg = createReq.pTsma;
+ uint32_t contLen = (uint32_t)(htonl(smaMsg->contLen) - sizeof(SMsgHead));
+ if (vnodeProcessCreateTSma(pImpl, POINTER_SHIFT(smaMsg, sizeof(SMsgHead)), contLen) < 0) {
+ dError("vgId:%d, failed to create tsma since %s", createReq.vgId, terrstr());
+ code = terrno;
+ goto _OVER;
+ };
+ }
+
code = vnodeStart(pImpl);
if (code != 0) {
dError("vgId:%d, failed to start sync since %s", createReq.vgId, terrstr());
@@ -228,7 +244,10 @@ int32_t vmProcessCreateVnodeReq(SVnodeMgmt *pMgmt, SRpcMsg *pMsg) {
}
code = vmWriteVnodeListToFile(pMgmt);
- if (code != 0) goto _OVER;
+ if (code != 0) {
+ code = terrno;
+ goto _OVER;
+ }
_OVER:
if (code != 0) {
@@ -314,8 +333,9 @@ SArray *vmGetMsgHandles() {
if (dmSetMgmtHandle(pArray, TDMT_VND_TASK_DISPATCH, vmPutNodeMsgToFetchQueue, 0) == NULL) goto _OVER;
if (dmSetMgmtHandle(pArray, TDMT_VND_TASK_RECOVER, vmPutNodeMsgToFetchQueue, 0) == NULL) goto _OVER;
- if (dmSetMgmtHandle(pArray, TDMT_VND_ALTER_VNODE, vmPutNodeMsgToWriteQueue, 0) == NULL) goto _OVER;
- if (dmSetMgmtHandle(pArray, TDMT_VND_COMPACT_VNODE, vmPutNodeMsgToWriteQueue, 0) == NULL) goto _OVER;
+ if (dmSetMgmtHandle(pArray, TDMT_VND_ALTER_REPLICA, vmPutNodeMsgToWriteQueue, 0) == NULL) goto _OVER;
+ if (dmSetMgmtHandle(pArray, TDMT_VND_ALTER_CONFIG, vmPutNodeMsgToWriteQueue, 0) == NULL) goto _OVER;
+ if (dmSetMgmtHandle(pArray, TDMT_VND_COMPACT, vmPutNodeMsgToWriteQueue, 0) == NULL) goto _OVER;
if (dmSetMgmtHandle(pArray, TDMT_DND_CREATE_VNODE, vmPutNodeMsgToMgmtQueue, 0) == NULL) goto _OVER;
if (dmSetMgmtHandle(pArray, TDMT_DND_DROP_VNODE, vmPutNodeMsgToMgmtQueue, 0) == NULL) goto _OVER;
diff --git a/source/dnode/mnode/impl/inc/mndDef.h b/source/dnode/mnode/impl/inc/mndDef.h
index d0c737ae5a..2f7c357aef 100644
--- a/source/dnode/mnode/impl/inc/mndDef.h
+++ b/source/dnode/mnode/impl/inc/mndDef.h
@@ -168,7 +168,7 @@ typedef struct {
int64_t createdTime;
int64_t updateTime;
SDnodeObj* pDnode;
- SQnodeLoad load;
+ SQnodeLoad load;
} SQnodeObj;
typedef struct {
@@ -403,26 +403,22 @@ int32_t tEncodeSMqOffsetObj(void** buf, const SMqOffsetObj* pOffset);
void* tDecodeSMqOffsetObj(void* buf, SMqOffsetObj* pOffset);
typedef struct {
- char name[TSDB_TOPIC_FNAME_LEN];
- char db[TSDB_DB_FNAME_LEN];
- int64_t createTime;
- int64_t updateTime;
- int64_t uid;
- int64_t dbUid;
- int32_t version;
- int8_t subType; // column, db or stable
- // int8_t withTbName;
- // int8_t withSchema;
- // int8_t withTag;
+ char name[TSDB_TOPIC_FNAME_LEN];
+ char db[TSDB_DB_FNAME_LEN];
+ int64_t createTime;
+ int64_t updateTime;
+ int64_t uid;
+ int64_t dbUid;
+ int32_t version;
+ int8_t subType; // column, db or stable
SRWLatch lock;
- int32_t consumerCnt;
int32_t sqlLen;
int32_t astLen;
char* sql;
char* ast;
char* physicalPlan;
SSchemaWrapper schema;
- // int32_t refConsumerCnt;
+ int64_t stbUid;
} SMqTopicObj;
typedef struct {
@@ -476,14 +472,12 @@ int32_t tEncodeSMqConsumerEp(void** buf, const SMqConsumerEp* pEp);
void* tDecodeSMqConsumerEp(const void* buf, SMqConsumerEp* pEp);
typedef struct {
- char key[TSDB_SUBSCRIBE_KEY_LEN];
- SRWLatch lock;
- int64_t dbUid;
- int32_t vgNum;
- int8_t subType;
- // int8_t withTbName;
- // int8_t withSchema;
- // int8_t withTag;
+ char key[TSDB_SUBSCRIBE_KEY_LEN];
+ SRWLatch lock;
+ int64_t dbUid;
+ int32_t vgNum;
+ int8_t subType;
+ int64_t stbUid;
SHashObj* consumerHash; // consumerId -> SMqConsumerEp
SArray* unassignedVgs; // SArray
} SMqSubscribeObj;
@@ -535,7 +529,7 @@ typedef struct {
} SMqRebOutputObj;
typedef struct {
- char name[TSDB_TOPIC_FNAME_LEN];
+ char name[TSDB_STREAM_FNAME_LEN];
char sourceDb[TSDB_DB_FNAME_LEN];
char targetDb[TSDB_DB_FNAME_LEN];
char targetSTbName[TSDB_TABLE_FNAME_LEN];
diff --git a/source/dnode/mnode/impl/inc/mndTrans.h b/source/dnode/mnode/impl/inc/mndTrans.h
index 9b063fb44f..6d1f371083 100644
--- a/source/dnode/mnode/impl/inc/mndTrans.h
+++ b/source/dnode/mnode/impl/inc/mndTrans.h
@@ -61,7 +61,7 @@ int32_t mndTransAppendRedoAction(STrans *pTrans, STransAction *pAction);
int32_t mndTransAppendUndoAction(STrans *pTrans, STransAction *pAction);
void mndTransSetRpcRsp(STrans *pTrans, void *pCont, int32_t contLen);
void mndTransSetCb(STrans *pTrans, ETrnFunc startFunc, ETrnFunc stopFunc, void *param, int32_t paramLen);
-void mndTransSetDbInfo(STrans *pTrans, SDbObj *pDb);
+void mndTransSetDbName(STrans *pTrans, const char *dbname);
void mndTransSetSerial(STrans *pTrans);
int32_t mndTransPrepare(SMnode *pMnode, STrans *pTrans);
diff --git a/source/dnode/mnode/impl/inc/mndVgroup.h b/source/dnode/mnode/impl/inc/mndVgroup.h
index c9099b6b05..3f4f3f2053 100644
--- a/source/dnode/mnode/impl/inc/mndVgroup.h
+++ b/source/dnode/mnode/impl/inc/mndVgroup.h
@@ -36,7 +36,7 @@ SArray *mndBuildDnodesArray(SMnode *pMnode);
int32_t mndAddVnodeToVgroup(SMnode *pMnode, SVgObj *pVgroup, SArray *pArray);
int32_t mndRemoveVnodeFromVgroup(SMnode *pMnode, SVgObj *pVgroup, SArray *pArray, SVnodeGid *del1, SVnodeGid *del2);
-void *mndBuildCreateVnodeReq(SMnode *pMnode, SDnodeObj *pDnode, SDbObj *pDb, SVgObj *pVgroup, int32_t *pContLen);
+void *mndBuildCreateVnodeReq(SMnode *pMnode, SDnodeObj *pDnode, SDbObj *pDb, SVgObj *pVgroup, int32_t *pContLen, bool standby);
void *mndBuildDropVnodeReq(SMnode *pMnode, SDnodeObj *pDnode, SDbObj *pDb, SVgObj *pVgroup, int32_t *pContLen);
void *mndBuildAlterVnodeReq(SMnode *pMnode, SDbObj *pDb, SVgObj *pVgroup, int32_t *pContLen);
diff --git a/source/dnode/mnode/impl/src/mndConsumer.c b/source/dnode/mnode/impl/src/mndConsumer.c
index 0314891d59..1f8bf06993 100644
--- a/source/dnode/mnode/impl/src/mndConsumer.c
+++ b/source/dnode/mnode/impl/src/mndConsumer.c
@@ -306,6 +306,7 @@ static int32_t mndProcessAskEpReq(SRpcMsg *pMsg) {
SMqTopicObj *pTopic = mndAcquireTopic(pMnode, topic);
ASSERT(pTopic);
taosRLockLatch(&pTopic->lock);
+ tstrncpy(topicEp.db, pTopic->db, TSDB_DB_FNAME_LEN);
topicEp.schema.nCols = pTopic->schema.nCols;
if (topicEp.schema.nCols) {
topicEp.schema.pSchema = taosMemoryCalloc(topicEp.schema.nCols, sizeof(SSchema));
diff --git a/source/dnode/mnode/impl/src/mndDb.c b/source/dnode/mnode/impl/src/mndDb.c
index 5d79708109..c062a2c552 100644
--- a/source/dnode/mnode/impl/src/mndDb.c
+++ b/source/dnode/mnode/impl/src/mndDb.c
@@ -261,7 +261,7 @@ void mndReleaseDb(SMnode *pMnode, SDbObj *pDb) {
sdbRelease(pSdb, pDb);
}
-static int32_t mndAddCreateVnodeAction(SMnode *pMnode, STrans *pTrans, SDbObj *pDb, SVgObj *pVgroup, SVnodeGid *pVgid) {
+static int32_t mndAddCreateVnodeAction(SMnode *pMnode, STrans *pTrans, SDbObj *pDb, SVgObj *pVgroup, SVnodeGid *pVgid, bool standby) {
STransAction action = {0};
SDnodeObj *pDnode = mndAcquireDnode(pMnode, pVgid->dnodeId);
@@ -270,7 +270,7 @@ static int32_t mndAddCreateVnodeAction(SMnode *pMnode, STrans *pTrans, SDbObj *p
mndReleaseDnode(pMnode, pDnode);
int32_t contLen = 0;
- void *pReq = mndBuildCreateVnodeReq(pMnode, pDnode, pDb, pVgroup, &contLen);
+ void *pReq = mndBuildCreateVnodeReq(pMnode, pDnode, pDb, pVgroup, &contLen, standby);
if (pReq == NULL) return -1;
action.pCont = pReq;
@@ -286,7 +286,7 @@ static int32_t mndAddCreateVnodeAction(SMnode *pMnode, STrans *pTrans, SDbObj *p
return 0;
}
-static int32_t mndAddAlterVnodeAction(SMnode *pMnode, STrans *pTrans, SDbObj *pDb, SVgObj *pVgroup) {
+static int32_t mndAddAlterVnodeAction(SMnode *pMnode, STrans *pTrans, SDbObj *pDb, SVgObj *pVgroup, tmsg_t msgType) {
STransAction action = {0};
action.epSet = mndGetVgroupEpset(pMnode, pVgroup);
@@ -296,7 +296,7 @@ static int32_t mndAddAlterVnodeAction(SMnode *pMnode, STrans *pTrans, SDbObj *pD
action.pCont = pReq;
action.contLen = contLen;
- action.msgType = TDMT_VND_ALTER_VNODE;
+ action.msgType = msgType;
if (mndTransAppendRedoAction(pTrans, &action) != 0) {
taosMemoryFree(pReq);
@@ -388,7 +388,7 @@ static int32_t mndCheckDbCfg(SMnode *pMnode, SDbCfg *pCfg) {
}
terrno = 0;
- return TSDB_CODE_SUCCESS;
+ return terrno;
}
static void mndSetDefaultDbCfg(SDbCfg *pCfg) {
@@ -467,7 +467,7 @@ static int32_t mndSetCreateDbRedoActions(SMnode *pMnode, STrans *pTrans, SDbObj
for (int32_t vn = 0; vn < pVgroup->replica; ++vn) {
SVnodeGid *pVgid = pVgroup->vnodeGid + vn;
- if (mndAddCreateVnodeAction(pMnode, pTrans, pDb, pVgroup, pVgid) != 0) {
+ if (mndAddCreateVnodeAction(pMnode, pTrans, pDb, pVgroup, pVgid, false) != 0) {
return -1;
}
}
@@ -550,7 +550,7 @@ static int32_t mndCreateDb(SMnode *pMnode, SRpcMsg *pReq, SCreateDbReq *pCreate,
mDebug("trans:%d, used to create db:%s", pTrans->id, pCreate->db);
- mndTransSetDbInfo(pTrans, &dbObj);
+ mndTransSetDbName(pTrans, dbObj.name);
if (mndSetCreateDbRedoLogs(pMnode, pTrans, &dbObj, pVgroups) != 0) goto _OVER;
if (mndSetCreateDbUndoLogs(pMnode, pTrans, &dbObj, pVgroups) != 0) goto _OVER;
if (mndSetCreateDbCommitLogs(pMnode, pTrans, &dbObj, pVgroups) != 0) goto _OVER;
@@ -688,29 +688,37 @@ static int32_t mndSetDbCfgFromAlterDbReq(SDbObj *pDb, SAlterDbReq *pAlter) {
static int32_t mndSetAlterDbRedoLogs(SMnode *pMnode, STrans *pTrans, SDbObj *pOld, SDbObj *pNew) {
SSdbRaw *pRedoRaw = mndDbActionEncode(pOld);
if (pRedoRaw == NULL) return -1;
- if (mndTransAppendRedolog(pTrans, pRedoRaw) != 0) return -1;
- if (sdbSetRawStatus(pRedoRaw, SDB_STATUS_READY) != 0) return -1;
+ if (mndTransAppendRedolog(pTrans, pRedoRaw) != 0) {
+ sdbFreeRaw(pRedoRaw);
+ return -1;
+ }
+ sdbSetRawStatus(pRedoRaw, SDB_STATUS_READY);
return 0;
}
static int32_t mndSetAlterDbCommitLogs(SMnode *pMnode, STrans *pTrans, SDbObj *pOld, SDbObj *pNew) {
SSdbRaw *pCommitRaw = mndDbActionEncode(pNew);
if (pCommitRaw == NULL) return -1;
- if (mndTransAppendCommitlog(pTrans, pCommitRaw) != 0) return -1;
- if (sdbSetRawStatus(pCommitRaw, SDB_STATUS_READY) != 0) return -1;
+ if (mndTransAppendCommitlog(pTrans, pCommitRaw) != 0) {
+ sdbFreeRaw(pCommitRaw);
+ return -1;
+ }
+ sdbSetRawStatus(pCommitRaw, SDB_STATUS_READY);
return 0;
}
static int32_t mndBuildAlterVgroupAction(SMnode *pMnode, STrans *pTrans, SDbObj *pDb, SVgObj *pVgroup, SArray *pArray) {
if (pVgroup->replica <= 0 || pVgroup->replica == pDb->cfg.replications) {
- if (mndAddAlterVnodeAction(pMnode, pTrans, pDb, pVgroup) != 0) {
+ if (mndAddAlterVnodeAction(pMnode, pTrans, pDb, pVgroup, TDMT_VND_ALTER_CONFIG) != 0) {
return -1;
}
} else {
SVgObj newVgroup = {0};
memcpy(&newVgroup, pVgroup, sizeof(SVgObj));
+ mndTransSetSerial(pTrans);
+
if (newVgroup.replica < pDb->cfg.replications) {
mInfo("db:%s, vgId:%d, will add 2 vnodes, vn:0 dnode:%d", pVgroup->dbName, pVgroup->vgId,
pVgroup->vnodeGid[0].dnodeId);
@@ -720,9 +728,9 @@ static int32_t mndBuildAlterVgroupAction(SMnode *pMnode, STrans *pTrans, SDbObj
return -1;
}
newVgroup.replica = pDb->cfg.replications;
- if (mndAddAlterVnodeAction(pMnode, pTrans, pDb, &newVgroup) != 0) return -1;
- if (mndAddCreateVnodeAction(pMnode, pTrans, pDb, &newVgroup, &newVgroup.vnodeGid[1]) != 0) return -1;
- if (mndAddCreateVnodeAction(pMnode, pTrans, pDb, &newVgroup, &newVgroup.vnodeGid[2]) != 0) return -1;
+ if (mndAddCreateVnodeAction(pMnode, pTrans, pDb, &newVgroup, &newVgroup.vnodeGid[1], true) != 0) return -1;
+ if (mndAddCreateVnodeAction(pMnode, pTrans, pDb, &newVgroup, &newVgroup.vnodeGid[2], true) != 0) return -1;
+ if (mndAddAlterVnodeAction(pMnode, pTrans, pDb, &newVgroup, TDMT_VND_ALTER_REPLICA) != 0) return -1;
} else {
mInfo("db:%s, vgId:%d, will remove 2 vnodes", pVgroup->dbName, pVgroup->vgId);
@@ -733,15 +741,18 @@ static int32_t mndBuildAlterVgroupAction(SMnode *pMnode, STrans *pTrans, SDbObj
return -1;
}
newVgroup.replica = pDb->cfg.replications;
- if (mndAddAlterVnodeAction(pMnode, pTrans, pDb, &newVgroup) != 0) return -1;
+ if (mndAddAlterVnodeAction(pMnode, pTrans, pDb, &newVgroup, TDMT_VND_ALTER_REPLICA) != 0) return -1;
if (mndAddDropVnodeAction(pMnode, pTrans, pDb, &newVgroup, &del1, true) != 0) return -1;
if (mndAddDropVnodeAction(pMnode, pTrans, pDb, &newVgroup, &del2, true) != 0) return -1;
}
SSdbRaw *pVgRaw = mndVgroupActionEncode(&newVgroup);
if (pVgRaw == NULL) return -1;
- if (mndTransAppendCommitlog(pTrans, pVgRaw) != 0) return -1;
- if (sdbSetRawStatus(pVgRaw, SDB_STATUS_READY) != 0) return -1;
+ if (mndTransAppendCommitlog(pTrans, pVgRaw) != 0) {
+ sdbFreeRaw(pVgRaw);
+ return -1;
+ }
+ sdbSetRawStatus(pVgRaw, SDB_STATUS_READY);
}
return 0;
@@ -774,18 +785,16 @@ static int32_t mndSetAlterDbRedoActions(SMnode *pMnode, STrans *pTrans, SDbObj *
}
static int32_t mndAlterDb(SMnode *pMnode, SRpcMsg *pReq, SDbObj *pOld, SDbObj *pNew) {
- int32_t code = -1;
STrans *pTrans = mndTransCreate(pMnode, TRN_POLICY_RETRY, TRN_CONFLICT_DB, pReq);
- if (pTrans == NULL) goto _OVER;
-
+ if (pTrans == NULL) return -1;
mDebug("trans:%d, used to alter db:%s", pTrans->id, pOld->name);
- mndTransSetDbInfo(pTrans, pOld);
+ int32_t code = -1;
+ mndTransSetDbName(pTrans, pOld->name);
if (mndSetAlterDbRedoLogs(pMnode, pTrans, pOld, pNew) != 0) goto _OVER;
if (mndSetAlterDbCommitLogs(pMnode, pTrans, pOld, pNew) != 0) goto _OVER;
if (mndSetAlterDbRedoActions(pMnode, pTrans, pOld, pNew) != 0) goto _OVER;
if (mndTransPrepare(pMnode, pTrans) != 0) goto _OVER;
-
code = 0;
_OVER:
@@ -1040,7 +1049,7 @@ static int32_t mndDropDb(SMnode *pMnode, SRpcMsg *pReq, SDbObj *pDb) {
if (pTrans == NULL) goto _OVER;
mDebug("trans:%d, used to drop db:%s", pTrans->id, pDb->name);
- mndTransSetDbInfo(pTrans, pDb);
+ mndTransSetDbName(pTrans, pDb->name);
if (mndSetDropDbRedoLogs(pMnode, pTrans, pDb) != 0) goto _OVER;
if (mndSetDropDbCommitLogs(pMnode, pTrans, pDb) != 0) goto _OVER;
diff --git a/source/dnode/mnode/impl/src/mndDef.c b/source/dnode/mnode/impl/src/mndDef.c
index b45b6f9ee9..b6659e1632 100644
--- a/source/dnode/mnode/impl/src/mndDef.c
+++ b/source/dnode/mnode/impl/src/mndDef.c
@@ -395,10 +395,8 @@ SMqSubscribeObj *tCloneSubscribeObj(const SMqSubscribeObj *pSub) {
taosInitRWLatch(&pSubNew->lock);
pSubNew->dbUid = pSub->dbUid;
+ pSubNew->stbUid = pSub->stbUid;
pSubNew->subType = pSub->subType;
- /*pSubNew->withTbName = pSub->withTbName;*/
- /*pSubNew->withSchema = pSub->withSchema;*/
- /*pSubNew->withTag = pSub->withTag;*/
pSubNew->vgNum = pSub->vgNum;
pSubNew->consumerHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), false, HASH_NO_LOCK);
@@ -431,9 +429,7 @@ int32_t tEncodeSubscribeObj(void **buf, const SMqSubscribeObj *pSub) {
tlen += taosEncodeFixedI64(buf, pSub->dbUid);
tlen += taosEncodeFixedI32(buf, pSub->vgNum);
tlen += taosEncodeFixedI8(buf, pSub->subType);
- /*tlen += taosEncodeFixedI8(buf, pSub->withTbName);*/
- /*tlen += taosEncodeFixedI8(buf, pSub->withSchema);*/
- /*tlen += taosEncodeFixedI8(buf, pSub->withTag);*/
+ tlen += taosEncodeFixedI64(buf, pSub->stbUid);
void *pIter = NULL;
int32_t sz = taosHashGetSize(pSub->consumerHash);
@@ -458,9 +454,7 @@ void *tDecodeSubscribeObj(const void *buf, SMqSubscribeObj *pSub) {
buf = taosDecodeFixedI64(buf, &pSub->dbUid);
buf = taosDecodeFixedI32(buf, &pSub->vgNum);
buf = taosDecodeFixedI8(buf, &pSub->subType);
- /*buf = taosDecodeFixedI8(buf, &pSub->withTbName);*/
- /*buf = taosDecodeFixedI8(buf, &pSub->withSchema);*/
- /*buf = taosDecodeFixedI8(buf, &pSub->withTag);*/
+ buf = taosDecodeFixedI64(buf, &pSub->stbUid);
int32_t sz;
buf = taosDecodeFixedI32(buf, &sz);
diff --git a/source/dnode/mnode/impl/src/mndDnode.c b/source/dnode/mnode/impl/src/mndDnode.c
index 73d7eff04a..aeff018aa8 100644
--- a/source/dnode/mnode/impl/src/mndDnode.c
+++ b/source/dnode/mnode/impl/src/mndDnode.c
@@ -613,7 +613,7 @@ static int32_t mndProcessDropDnodeReq(SRpcMsg *pReq) {
pMObj = mndAcquireMnode(pMnode, dropReq.dnodeId);
if (pMObj != NULL) {
- terrno = TSDB_CODE_MND_MNODE_DEPLOYED;
+ terrno = TSDB_CODE_MND_MNODE_NOT_EXIST;
goto DROP_DNODE_OVER;
}
diff --git a/source/dnode/mnode/impl/src/mndMnode.c b/source/dnode/mnode/impl/src/mndMnode.c
index 4578d81efb..7c94a33ffe 100644
--- a/source/dnode/mnode/impl/src/mndMnode.c
+++ b/source/dnode/mnode/impl/src/mndMnode.c
@@ -392,11 +392,6 @@ static int32_t mndProcessCreateMnodeReq(SRpcMsg *pReq) {
mDebug("mnode:%d, start to create", createReq.dnodeId);
- if (sdbGetSize(pMnode->pSdb, SDB_MNODE) >= 3) {
- terrno = TSDB_CODE_MND_TOO_MANY_MNODES;
- goto _OVER;
- }
-
pObj = mndAcquireMnode(pMnode, createReq.dnodeId);
if (pObj != NULL) {
terrno = TSDB_CODE_MND_MNODE_ALREADY_EXIST;
@@ -405,12 +400,22 @@ static int32_t mndProcessCreateMnodeReq(SRpcMsg *pReq) {
goto _OVER;
}
+ if (sdbGetSize(pMnode->pSdb, SDB_MNODE) >= 3) {
+ terrno = TSDB_CODE_MND_TOO_MANY_MNODES;
+ goto _OVER;
+ }
+
pDnode = mndAcquireDnode(pMnode, createReq.dnodeId);
if (pDnode == NULL) {
terrno = TSDB_CODE_MND_DNODE_NOT_EXIST;
goto _OVER;
}
+ if (!mndIsDnodeOnline(pMnode, pDnode, taosGetTimestampMs())) {
+ terrno = TSDB_CODE_NODE_OFFLINE;
+ goto _OVER;
+ }
+
pUser = mndAcquireUser(pMnode, pReq->conn.user);
if (pUser == NULL) {
terrno = TSDB_CODE_MND_NO_USER_FROM_CONN;
@@ -632,11 +637,12 @@ static int32_t mndRetrieveMnodes(SRpcMsg *pReq, SShowObj *pShow, SSDataBlock *pB
int32_t numOfRows = 0;
int32_t cols = 0;
SMnodeObj *pObj = NULL;
+ ESdbStatus objStatus;
char *pWrite;
int64_t curMs = taosGetTimestampMs();
while (numOfRows < rows) {
- pShow->pIter = sdbFetch(pSdb, SDB_MNODE, pShow->pIter, (void **)&pObj);
+ pShow->pIter = sdbFetchAll(pSdb, SDB_MNODE, pShow->pIter, (void **)&pObj, &objStatus);
if (pShow->pIter == NULL) break;
cols = 0;
@@ -649,23 +655,26 @@ static int32_t mndRetrieveMnodes(SRpcMsg *pReq, SShowObj *pShow, SSDataBlock *pB
pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
colDataAppend(pColInfo, numOfRows, b1, false);
- bool online = mndIsDnodeOnline(pMnode, pObj->pDnode, curMs);
- const char *roles = NULL;
+ const char *roles = "OFFLINE";
if (pObj->id == pMnode->selfDnodeId) {
roles = syncStr(TAOS_SYNC_STATE_LEADER);
- } else {
- if (!online) {
- roles = "OFFLINE";
- } else {
- roles = syncStr(pObj->state);
- }
}
- char *b2 = taosMemoryCalloc(1, 12 + VARSTR_HEADER_SIZE);
+ if (pObj->pDnode && mndIsDnodeOnline(pMnode, pObj->pDnode, curMs)) {
+ roles = syncStr(pObj->state);
+ }
+ char b2[12 + VARSTR_HEADER_SIZE] = {0};
STR_WITH_MAXSIZE_TO_VARSTR(b2, roles, pShow->pMeta->pSchemas[cols].bytes);
-
pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
colDataAppend(pColInfo, numOfRows, (const char *)b2, false);
+ const char *status = "READY";
+ if (objStatus == SDB_STATUS_CREATING) status = "CREATING";
+ if (objStatus == SDB_STATUS_DROPPING) status = "DROPPING";
+ char b3[9 + VARSTR_HEADER_SIZE] = {0};
+ STR_WITH_MAXSIZE_TO_VARSTR(b3, status, pShow->pMeta->pSchemas[cols].bytes);
+ pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
+ colDataAppend(pColInfo, numOfRows, (const char *)b3, false);
+
pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
colDataAppend(pColInfo, numOfRows, (const char *)&pObj->createdTime, false);
diff --git a/source/dnode/mnode/impl/src/mndSma.c b/source/dnode/mnode/impl/src/mndSma.c
index 8b09674179..6cb70d1f27 100644
--- a/source/dnode/mnode/impl/src/mndSma.c
+++ b/source/dnode/mnode/impl/src/mndSma.c
@@ -426,7 +426,7 @@ static int32_t mndSetCreateSmaVgroupRedoActions(SMnode *pMnode, STrans *pTrans,
pVgroup->pTsma = pSmaReq;
int32_t contLen = 0;
- void *pReq = mndBuildCreateVnodeReq(pMnode, pDnode, pDb, pVgroup, &contLen);
+ void *pReq = mndBuildCreateVnodeReq(pMnode, pDnode, pDb, pVgroup, &contLen, false);
taosMemoryFreeClear(pSmaReq);
if (pReq == NULL) return -1;
@@ -512,7 +512,7 @@ static int32_t mndCreateSma(SMnode *pMnode, SRpcMsg *pReq, SMCreateSmaReq *pCrea
if (pTrans == NULL) goto _OVER;
mDebug("trans:%d, used to create sma:%s", pTrans->id, pCreate->name);
- mndTransSetDbInfo(pTrans, pDb);
+ mndTransSetDbName(pTrans, pDb->name);
mndTransSetSerial(pTrans);
if (mndSetCreateSmaRedoLogs(pMnode, pTrans, &smaObj) != 0) goto _OVER;
@@ -757,7 +757,7 @@ static int32_t mndDropSma(SMnode *pMnode, SRpcMsg *pReq, SDbObj *pDb, SSmaObj *p
if (pTrans == NULL) goto _OVER;
mDebug("trans:%d, used to drop sma:%s", pTrans->id, pSma->name);
- mndTransSetDbInfo(pTrans, pDb);
+ mndTransSetDbName(pTrans, pDb->name);
if (mndSetDropSmaRedoLogs(pMnode, pTrans, pSma) != 0) goto _OVER;
if (mndSetDropSmaVgroupRedoLogs(pMnode, pTrans, pVgroup) != 0) goto _OVER;
diff --git a/source/dnode/mnode/impl/src/mndStb.c b/source/dnode/mnode/impl/src/mndStb.c
index aa8789829c..556837f397 100644
--- a/source/dnode/mnode/impl/src/mndStb.c
+++ b/source/dnode/mnode/impl/src/mndStb.c
@@ -754,7 +754,7 @@ _OVER:
}
int32_t mndAddStbToTrans(SMnode *pMnode, STrans *pTrans, SDbObj *pDb, SStbObj *pStb) {
- mndTransSetDbInfo(pTrans, pDb);
+ mndTransSetDbName(pTrans, pDb->name);
if (mndSetCreateStbRedoLogs(pMnode, pTrans, pDb, pStb) != 0) return -1;
if (mndSetCreateStbUndoLogs(pMnode, pTrans, pDb, pStb) != 0) return -1;
if (mndSetCreateStbCommitLogs(pMnode, pTrans, pDb, pStb) != 0) return -1;
@@ -1375,7 +1375,7 @@ static int32_t mndAlterStb(SMnode *pMnode, SRpcMsg *pReq, const SMAlterStbReq *p
if (pTrans == NULL) goto _OVER;
mDebug("trans:%d, used to alter stb:%s", pTrans->id, pAlter->name);
- mndTransSetDbInfo(pTrans, pDb);
+ mndTransSetDbName(pTrans, pDb->name);
if (needRsp) {
void* pCont = NULL;
@@ -1528,7 +1528,7 @@ static int32_t mndDropStb(SMnode *pMnode, SRpcMsg *pReq, SDbObj *pDb, SStbObj *p
if (pTrans == NULL) goto _OVER;
mDebug("trans:%d, used to drop stb:%s", pTrans->id, pStb->name);
- mndTransSetDbInfo(pTrans, pDb);
+ mndTransSetDbName(pTrans, pDb->name);
if (mndSetDropStbRedoLogs(pMnode, pTrans, pStb) != 0) goto _OVER;
if (mndSetDropStbCommitLogs(pMnode, pTrans, pStb) != 0) goto _OVER;
diff --git a/source/dnode/mnode/impl/src/mndSubscribe.c b/source/dnode/mnode/impl/src/mndSubscribe.c
index fc736809fd..41065a3fdd 100644
--- a/source/dnode/mnode/impl/src/mndSubscribe.c
+++ b/source/dnode/mnode/impl/src/mndSubscribe.c
@@ -93,10 +93,8 @@ static SMqSubscribeObj *mndCreateSub(SMnode *pMnode, const SMqTopicObj *pTopic,
return NULL;
}
pSub->dbUid = pTopic->dbUid;
+ pSub->stbUid = pTopic->stbUid;
pSub->subType = pTopic->subType;
- /*pSub->withTbName = pTopic->withTbName;*/
- /*pSub->withSchema = pTopic->withSchema;*/
- /*pSub->withTag = pTopic->withTag;*/
ASSERT(pSub->unassignedVgs->size == 0);
ASSERT(taosHashGetSize(pSub->consumerHash) == 0);
@@ -121,9 +119,7 @@ static int32_t mndBuildSubChangeReq(void **pBuf, int32_t *pLen, const SMqSubscri
req.vgId = pRebVg->pVgEp->vgId;
req.qmsg = pRebVg->pVgEp->qmsg;
req.subType = pSub->subType;
- /*req.withTbName = pSub->withTbName;*/
- /*req.withSchema = pSub->withSchema;*/
- /*req.withTag = pSub->withTag;*/
+ req.suid = pSub->stbUid;
strncpy(req.subKey, pSub->key, TSDB_SUBSCRIBE_KEY_LEN);
int32_t tlen = sizeof(SMsgHead) + tEncodeSMqRebVgReq(NULL, &req);
diff --git a/source/dnode/mnode/impl/src/mndTopic.c b/source/dnode/mnode/impl/src/mndTopic.c
index 446992a245..21b5e37e1e 100644
--- a/source/dnode/mnode/impl/src/mndTopic.c
+++ b/source/dnode/mnode/impl/src/mndTopic.c
@@ -96,11 +96,8 @@ SSdbRaw *mndTopicActionEncode(SMqTopicObj *pTopic) {
SDB_SET_INT64(pRaw, dataPos, pTopic->dbUid, TOPIC_ENCODE_OVER);
SDB_SET_INT32(pRaw, dataPos, pTopic->version, TOPIC_ENCODE_OVER);
SDB_SET_INT8(pRaw, dataPos, pTopic->subType, TOPIC_ENCODE_OVER);
- /*SDB_SET_INT8(pRaw, dataPos, pTopic->withTbName, TOPIC_ENCODE_OVER);*/
- /*SDB_SET_INT8(pRaw, dataPos, pTopic->withSchema, TOPIC_ENCODE_OVER);*/
- /*SDB_SET_INT8(pRaw, dataPos, pTopic->withTag, TOPIC_ENCODE_OVER);*/
- SDB_SET_INT32(pRaw, dataPos, pTopic->consumerCnt, TOPIC_ENCODE_OVER);
+ SDB_SET_INT64(pRaw, dataPos, pTopic->stbUid, TOPIC_ENCODE_OVER);
SDB_SET_INT32(pRaw, dataPos, pTopic->sqlLen, TOPIC_ENCODE_OVER);
SDB_SET_BINARY(pRaw, dataPos, pTopic->sql, pTopic->sqlLen, TOPIC_ENCODE_OVER);
SDB_SET_INT32(pRaw, dataPos, pTopic->astLen, TOPIC_ENCODE_OVER);
@@ -122,8 +119,6 @@ SSdbRaw *mndTopicActionEncode(SMqTopicObj *pTopic) {
SDB_SET_BINARY(pRaw, dataPos, swBuf, schemaLen, TOPIC_ENCODE_OVER);
}
- /*SDB_SET_INT32(pRaw, dataPos, pTopic->refConsumerCnt, TOPIC_ENCODE_OVER);*/
-
SDB_SET_RESERVE(pRaw, dataPos, MND_TOPIC_RESERVE_SIZE, TOPIC_ENCODE_OVER);
SDB_SET_DATALEN(pRaw, dataPos, TOPIC_ENCODE_OVER);
@@ -168,12 +163,8 @@ SSdbRow *mndTopicActionDecode(SSdbRaw *pRaw) {
SDB_GET_INT64(pRaw, dataPos, &pTopic->dbUid, TOPIC_DECODE_OVER);
SDB_GET_INT32(pRaw, dataPos, &pTopic->version, TOPIC_DECODE_OVER);
SDB_GET_INT8(pRaw, dataPos, &pTopic->subType, TOPIC_DECODE_OVER);
- /*SDB_GET_INT8(pRaw, dataPos, &pTopic->withTbName, TOPIC_DECODE_OVER);*/
- /*SDB_GET_INT8(pRaw, dataPos, &pTopic->withSchema, TOPIC_DECODE_OVER);*/
- /*SDB_GET_INT8(pRaw, dataPos, &pTopic->withTag, TOPIC_DECODE_OVER);*/
-
- SDB_GET_INT32(pRaw, dataPos, &pTopic->consumerCnt, TOPIC_DECODE_OVER);
+ SDB_GET_INT64(pRaw, dataPos, &pTopic->stbUid, TOPIC_DECODE_OVER);
SDB_GET_INT32(pRaw, dataPos, &pTopic->sqlLen, TOPIC_DECODE_OVER);
pTopic->sql = taosMemoryCalloc(pTopic->sqlLen, sizeof(char));
if (pTopic->sql == NULL) {
@@ -222,8 +213,6 @@ SSdbRow *mndTopicActionDecode(SSdbRaw *pRaw) {
pTopic->schema.pSchema = NULL;
}
- /*SDB_GET_INT32(pRaw, dataPos, &pTopic->refConsumerCnt, TOPIC_DECODE_OVER);*/
-
SDB_GET_RESERVE(pRaw, dataPos, MND_TOPIC_RESERVE_SIZE, TOPIC_DECODE_OVER);
terrno = TSDB_CODE_SUCCESS;
@@ -254,8 +243,6 @@ static int32_t mndTopicActionUpdate(SSdb *pSdb, SMqTopicObj *pOldTopic, SMqTopic
atomic_exchange_64(&pOldTopic->updateTime, pNewTopic->updateTime);
atomic_exchange_32(&pOldTopic->version, pNewTopic->version);
- /*atomic_store_32(&pOldTopic->refConsumerCnt, pNewTopic->refConsumerCnt);*/
-
/*taosWLockLatch(&pOldTopic->lock);*/
// TODO handle update
@@ -278,18 +265,6 @@ void mndReleaseTopic(SMnode *pMnode, SMqTopicObj *pTopic) {
sdbRelease(pSdb, pTopic);
}
-#if 0
-static SDbObj *mndAcquireDbByTopic(SMnode *pMnode, char *topicName) {
- SName name = {0};
- tNameFromString(&name, topicName, T_NAME_ACCT | T_NAME_DB | T_NAME_TABLE);
-
- char db[TSDB_TOPIC_FNAME_LEN] = {0};
- tNameGetFullDbName(&name, db);
-
- return mndAcquireDb(pMnode, db);
-}
-#endif
-
static SDDropTopicReq *mndBuildDropTopicMsg(SMnode *pMnode, SVgObj *pVgroup, SMqTopicObj *pTopic) {
int32_t contLen = sizeof(SDDropTopicReq);
@@ -341,8 +316,6 @@ static int32_t mndCreateTopic(SMnode *pMnode, SRpcMsg *pReq, SCMCreateTopicReq *
if (pCreate->subType == TOPIC_SUB_TYPE__COLUMN) {
topicObj.ast = strdup(pCreate->ast);
topicObj.astLen = strlen(pCreate->ast) + 1;
- /*topicObj.withTbName = pCreate->withTbName;*/
- /*topicObj.withSchema = pCreate->withSchema;*/
SNode *pAst = NULL;
if (nodesStringToNode(pCreate->ast, &pAst) != 0) {
@@ -375,13 +348,16 @@ static int32_t mndCreateTopic(SMnode *pMnode, SRpcMsg *pReq, SCMCreateTopicReq *
taosMemoryFree(topicObj.sql);
return -1;
}
- /*} else if (pCreate->subType == TOPIC_SUB_TYPE__DB) {*/
- /*topicObj.ast = NULL;*/
- /*topicObj.astLen = 0;*/
- /*topicObj.physicalPlan = NULL;*/
- /*topicObj.withTbName = 1;*/
- /*topicObj.withSchema = 1;*/
+ } else if (pCreate->subType == TOPIC_SUB_TYPE__TABLE) {
+ SStbObj *pStb = mndAcquireStb(pMnode, pCreate->subStbName);
+ topicObj.stbUid = pStb->uid;
}
+ /*} else if (pCreate->subType == TOPIC_SUB_TYPE__DB) {*/
+ /*topicObj.ast = NULL;*/
+ /*topicObj.astLen = 0;*/
+ /*topicObj.physicalPlan = NULL;*/
+ /*topicObj.withTbName = 1;*/
+ /*topicObj.withSchema = 1;*/
STrans *pTrans = mndTransCreate(pMnode, TRN_POLICY_ROLLBACK, TRN_CONFLICT_NOTHING, pReq);
if (pTrans == NULL) {
diff --git a/source/dnode/mnode/impl/src/mndTrans.c b/source/dnode/mnode/impl/src/mndTrans.c
index bad513a89d..bbee59090d 100644
--- a/source/dnode/mnode/impl/src/mndTrans.c
+++ b/source/dnode/mnode/impl/src/mndTrans.c
@@ -344,7 +344,7 @@ static SSdbRow *mndTransActionDecode(SSdbRaw *pRaw) {
SDB_GET_INT32(pRaw, dataPos, &dataLen, _OVER)
action.pRaw = taosMemoryMalloc(dataLen);
if (action.pRaw == NULL) goto _OVER;
- mTrace("raw:%p, is created", pData);
+ mTrace("raw:%p, is created", action.pRaw);
SDB_GET_BINARY(pRaw, dataPos, (void *)action.pRaw, dataLen, _OVER);
if (taosArrayPush(pTrans->commitActions, &action) == NULL) goto _OVER;
action.pRaw = NULL;
@@ -619,9 +619,7 @@ void mndTransSetCb(STrans *pTrans, ETrnFunc startFunc, ETrnFunc stopFunc, void *
pTrans->paramLen = paramLen;
}
-void mndTransSetDbInfo(STrans *pTrans, SDbObj *pDb) {
- memcpy(pTrans->dbname, pDb->name, TSDB_DB_FNAME_LEN);
-}
+void mndTransSetDbName(STrans *pTrans, const char *dbname) { memcpy(pTrans->dbname, dbname, TSDB_DB_FNAME_LEN); }
void mndTransSetSerial(STrans *pTrans) { pTrans->exec = TRN_EXEC_SERIAL; }
@@ -753,22 +751,30 @@ static void mndTransSendRpcRsp(SMnode *pMnode, STrans *pTrans) {
sendRsp = true;
}
} else {
- if (pTrans->stage == TRN_STAGE_REDO_ACTION && pTrans->failedTimes > 6) {
+ if (pTrans->stage == TRN_STAGE_REDO_ACTION && pTrans->failedTimes > 3) {
if (code == 0) code = TSDB_CODE_MND_TRANS_UNKNOW_ERROR;
sendRsp = true;
}
}
if (sendRsp && pTrans->rpcInfo.handle != NULL) {
- void *rpcCont = rpcMallocCont(pTrans->rpcRspLen);
- if (rpcCont != NULL) {
- memcpy(rpcCont, pTrans->rpcRsp, pTrans->rpcRspLen);
- }
- taosMemoryFree(pTrans->rpcRsp);
-
mDebug("trans:%d, send rsp, code:0x%x stage:%s app:%p", pTrans->id, code, mndTransStr(pTrans->stage),
pTrans->rpcInfo.ahandle);
- SRpcMsg rspMsg = {.code = code, .pCont = rpcCont, .contLen = pTrans->rpcRspLen, .info = pTrans->rpcInfo};
+ if (code == TSDB_CODE_RPC_NETWORK_UNAVAIL) {
+ code = TSDB_CODE_RPC_INDIRECT_NETWORK_UNAVAIL;
+ }
+ SRpcMsg rspMsg = {.code = code, .info = pTrans->rpcInfo};
+
+ if (pTrans->rpcRspLen != 0) {
+ void *rpcCont = rpcMallocCont(pTrans->rpcRspLen);
+ if (rpcCont != NULL) {
+ memcpy(rpcCont, pTrans->rpcRsp, pTrans->rpcRspLen);
+ rspMsg.pCont = rpcCont;
+ rspMsg.contLen = pTrans->rpcRspLen;
+ }
+ taosMemoryFree(pTrans->rpcRsp);
+ }
+
tmsgSendRsp(&rspMsg);
pTrans->rpcInfo.handle = NULL;
pTrans->rpcRsp = NULL;
@@ -1000,6 +1006,9 @@ static int32_t mndTransExecuteRedoActionsSerial(SMnode *pMnode, STrans *pTrans)
if (pAction->msgReceived) {
if (pAction->errCode != 0 && pAction->errCode != pAction->acceptableCode) {
code = pAction->errCode;
+ pAction->msgSent = 0;
+ pAction->msgReceived = 0;
+ mDebug("trans:%d, %s:%d execute status is reset", pTrans->id, mndTransStr(pAction->stage), action);
}
} else {
code = TSDB_CODE_ACTION_IN_PROGRESS;
@@ -1025,18 +1034,23 @@ static int32_t mndTransExecuteRedoActionsSerial(SMnode *pMnode, STrans *pTrans)
}
if (code == 0) {
+ pTrans->code = 0;
pTrans->redoActionPos++;
mDebug("trans:%d, %s:%d is executed and need sync to other mnodes", pTrans->id, mndTransStr(pAction->stage),
pAction->id);
code = mndTransSync(pMnode, pTrans);
if (code != 0) {
- mError("trans:%d, failed to sync redoActionPos since %s", pTrans->id, terrstr());
+ pTrans->code = terrno;
+ mError("trans:%d, %s:%d is executed and failed to sync to other mnodes since %s", pTrans->id,
+ mndTransStr(pAction->stage), pAction->id, terrstr());
break;
}
} else if (code == TSDB_CODE_ACTION_IN_PROGRESS) {
mDebug("trans:%d, %s:%d is in progress and wait it finish", pTrans->id, mndTransStr(pAction->stage), pAction->id);
break;
} else {
+ terrno = code;
+ pTrans->code = code;
mError("trans:%d, %s:%d failed to execute since %s", pTrans->id, mndTransStr(pAction->stage), pAction->id,
terrstr());
break;
@@ -1239,19 +1253,8 @@ int32_t mndKillTrans(SMnode *pMnode, STrans *pTrans) {
return -1;
}
- int32_t size = taosArrayGetSize(pArray);
-
- for (int32_t i = 0; i < size; ++i) {
+ for (int32_t i = 0; i < taosArrayGetSize(pArray); ++i) {
STransAction *pAction = taosArrayGet(pArray, i);
- if (pAction == NULL) continue;
-
- if (pAction->msgReceived == 0) {
- mInfo("trans:%d, %s:%d set processed for kill msg received", pTrans->id, mndTransStr(pAction->stage), i);
- pAction->msgSent = 1;
- pAction->msgReceived = 1;
- pAction->errCode = 0;
- }
-
if (pAction->errCode != 0) {
mInfo("trans:%d, %s:%d set processed for kill msg received, errCode from %s to success", pTrans->id,
mndTransStr(pAction->stage), i, tstrerror(pAction->errCode));
@@ -1290,9 +1293,7 @@ static int32_t mndProcessKillTransReq(SRpcMsg *pReq) {
pTrans = mndAcquireTrans(pMnode, killReq.transId);
if (pTrans == NULL) {
- terrno = TSDB_CODE_MND_TRANS_NOT_EXIST;
- mError("trans:%d, failed to kill since %s", killReq.transId, terrstr());
- return -1;
+ goto _OVER;
}
code = mndKillTrans(pMnode, pTrans);
@@ -1300,9 +1301,9 @@ static int32_t mndProcessKillTransReq(SRpcMsg *pReq) {
_OVER:
if (code != 0) {
mError("trans:%d, failed to kill since %s", killReq.transId, terrstr());
- return -1;
}
+ mndReleaseUser(pMnode, pUser);
mndReleaseTrans(pMnode, pTrans);
return code;
}
diff --git a/source/dnode/mnode/impl/src/mndVgroup.c b/source/dnode/mnode/impl/src/mndVgroup.c
index b5f308fef2..9262aa167b 100644
--- a/source/dnode/mnode/impl/src/mndVgroup.c
+++ b/source/dnode/mnode/impl/src/mndVgroup.c
@@ -51,9 +51,10 @@ int32_t mndInitVgroup(SMnode *pMnode) {
};
mndSetMsgHandle(pMnode, TDMT_DND_CREATE_VNODE_RSP, mndProcessCreateVnodeRsp);
- mndSetMsgHandle(pMnode, TDMT_VND_ALTER_VNODE_RSP, mndProcessAlterVnodeRsp);
+ mndSetMsgHandle(pMnode, TDMT_VND_ALTER_REPLICA_RSP, mndProcessAlterVnodeRsp);
+ mndSetMsgHandle(pMnode, TDMT_VND_ALTER_CONFIG_RSP, mndProcessAlterVnodeRsp);
mndSetMsgHandle(pMnode, TDMT_DND_DROP_VNODE_RSP, mndProcessDropVnodeRsp);
- mndSetMsgHandle(pMnode, TDMT_VND_COMPACT_VNODE_RSP, mndProcessCompactVnodeRsp);
+ mndSetMsgHandle(pMnode, TDMT_VND_COMPACT_RSP, mndProcessCompactVnodeRsp);
mndAddShowRetrieveHandle(pMnode, TSDB_MGMT_TABLE_VGROUP, mndRetrieveVgroups);
mndAddShowFreeIterHandle(pMnode, TSDB_MGMT_TABLE_VGROUP, mndCancelGetNextVgroup);
@@ -188,10 +189,10 @@ void mndReleaseVgroup(SMnode *pMnode, SVgObj *pVgroup) {
sdbRelease(pSdb, pVgroup);
}
-void *mndBuildCreateVnodeReq(SMnode *pMnode, SDnodeObj *pDnode, SDbObj *pDb, SVgObj *pVgroup, int32_t *pContLen) {
+void *mndBuildCreateVnodeReq(SMnode *pMnode, SDnodeObj *pDnode, SDbObj *pDb, SVgObj *pVgroup, int32_t *pContLen,
+ bool standby) {
SCreateVnodeReq createReq = {0};
createReq.vgId = pVgroup->vgId;
- createReq.dnodeId = pDnode->id;
memcpy(createReq.db, pDb->name, TSDB_DB_FNAME_LEN);
createReq.dbUid = pDb->uid;
createReq.vgVersion = pVgroup->version;
@@ -218,6 +219,7 @@ void *mndBuildCreateVnodeReq(SMnode *pMnode, SDnodeObj *pDnode, SDbObj *pDb, SVg
createReq.hashMethod = pDb->cfg.hashMethod;
createReq.numOfRetensions = pDb->cfg.numOfRetensions;
createReq.pRetensions = pDb->cfg.pRetensions;
+ createReq.standby = standby;
createReq.isTsma = pVgroup->isTsma;
createReq.pTsma = pVgroup->pTsma;
@@ -276,7 +278,6 @@ void *mndBuildAlterVnodeReq(SMnode *pMnode, SDbObj *pDb, SVgObj *pVgroup, int32_
alterReq.strict = pDb->cfg.strict;
alterReq.cacheLastRow = pDb->cfg.cacheLastRow;
alterReq.replica = pVgroup->replica;
- alterReq.selfIndex = -1;
for (int32_t v = 0; v < pVgroup->replica; ++v) {
SReplica *pReplica = &alterReq.replicas[v];
@@ -292,13 +293,6 @@ void *mndBuildAlterVnodeReq(SMnode *pMnode, SDbObj *pDb, SVgObj *pVgroup, int32_
mndReleaseDnode(pMnode, pVgidDnode);
}
-#if 0
- if (alterReq.selfIndex == -1) {
- terrno = TSDB_CODE_MND_APP_ERROR;
- return NULL;
- }
-#endif
-
int32_t contLen = tSerializeSAlterVnodeReq(NULL, 0, &alterReq);
if (contLen < 0) {
terrno = TSDB_CODE_OUT_OF_MEMORY;
@@ -538,7 +532,7 @@ int32_t mndAddVnodeToVgroup(SMnode *pMnode, SVgObj *pVgroup, SArray *pArray) {
SVnodeGid *pVgid = &pVgroup->vnodeGid[maxPos];
pVgid->dnodeId = pDnode->id;
- pVgid->role = TAOS_SYNC_STATE_FOLLOWER;
+ pVgid->role = TAOS_SYNC_STATE_ERROR;
pDnode->numOfVnodes++;
mInfo("db:%s, vgId:%d, vnode_index:%d dnode:%d is added", pVgroup->dbName, pVgroup->vgId, maxPos, pVgid->dnodeId);
@@ -551,14 +545,13 @@ int32_t mndAddVnodeToVgroup(SMnode *pMnode, SVgObj *pVgroup, SArray *pArray) {
}
int32_t mndRemoveVnodeFromVgroup(SMnode *pMnode, SVgObj *pVgroup, SArray *pArray, SVnodeGid *del1, SVnodeGid *del2) {
- int32_t removedNum = 0;
-
taosArraySort(pArray, (__compar_fn_t)mndCompareDnodeVnodes);
for (int32_t i = 0; i < taosArrayGetSize(pArray); ++i) {
SDnodeObj *pDnode = taosArrayGet(pArray, i);
mDebug("dnode:%d, equivalent vnodes:%d", pDnode->id, pDnode->numOfVnodes);
}
+ int32_t removedNum = 0;
for (int32_t d = taosArrayGetSize(pArray) - 1; d >= 0; --d) {
SDnodeObj *pDnode = taosArrayGet(pArray, d);
@@ -664,6 +657,7 @@ static int32_t mndRetrieveVgroups(SRpcMsg *pReq, SShowObj *pShow, SSDataBlock *p
int32_t numOfRows = 0;
SVgObj *pVgroup = NULL;
int32_t cols = 0;
+ int64_t curMs = taosGetTimestampMs();
SDbObj *pDb = NULL;
if (strlen(pShow->db) > 0) {
@@ -703,12 +697,15 @@ static int32_t mndRetrieveVgroups(SRpcMsg *pReq, SShowObj *pShow, SSDataBlock *p
if (i < pVgroup->replica) {
colDataAppend(pColInfo, numOfRows, (const char *)&pVgroup->vnodeGid[i].dnodeId, false);
+ bool online = false;
+ SDnodeObj *pDnode = mndAcquireDnode(pMnode, pVgroup->vnodeGid[i].dnodeId);
+ if (pDnode != NULL) {
+ online = mndIsDnodeOnline(pMnode, pDnode, curMs);
+ mndReleaseDnode(pMnode, pDnode);
+ }
+
char buf1[20] = {0};
- SDnodeObj *pDnodeObj = mndAcquireDnode(pMnode, pVgroup->vnodeGid[i].dnodeId);
- ASSERT(pDnodeObj != NULL);
- bool isOffLine = !mndIsDnodeOnline(pMnode, pDnodeObj, taosGetTimestampMs());
- const char *role = isOffLine ? "OFFLINE" : syncStr(pVgroup->vnodeGid[i].role);
-
+ const char *role = online ? syncStr(pVgroup->vnodeGid[i].role) : "OFFLINE";
STR_WITH_MAXSIZE_TO_VARSTR(buf1, role, pShow->pMeta->pSchemas[cols].bytes);
pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
diff --git a/source/dnode/mnode/impl/test/trans/trans2.cpp b/source/dnode/mnode/impl/test/trans/trans2.cpp
index d518db2d38..022c82c73d 100644
--- a/source/dnode/mnode/impl/test/trans/trans2.cpp
+++ b/source/dnode/mnode/impl/test/trans/trans2.cpp
@@ -128,7 +128,7 @@ class MndTestTrans2 : public ::testing::Test {
mndTransSetCb(pTrans, TRANS_START_FUNC_TEST, TRANS_STOP_FUNC_TEST, param, strlen(param) + 1);
if (pDb != NULL) {
- mndTransSetDbInfo(pTrans, pDb);
+ mndTransSetDbName(pTrans, pDb->name);
}
int32_t code = mndTransPrepare(pMnode, pTrans);
@@ -201,7 +201,7 @@ class MndTestTrans2 : public ::testing::Test {
}
if (pDb != NULL) {
- mndTransSetDbInfo(pTrans, pDb);
+ mndTransSetDbName(pTrans, pDb->name);
}
int32_t code = mndTransPrepare(pMnode, pTrans);
diff --git a/source/dnode/mnode/sdb/inc/sdb.h b/source/dnode/mnode/sdb/inc/sdb.h
index 1fd0260d0d..4a00befa1e 100644
--- a/source/dnode/mnode/sdb/inc/sdb.h
+++ b/source/dnode/mnode/sdb/inc/sdb.h
@@ -301,6 +301,7 @@ void sdbRelease(SSdb *pSdb, void *pObj);
* @return void* The next iterator of the table.
*/
void *sdbFetch(SSdb *pSdb, ESdbType type, void *pIter, void **ppObj);
+void *sdbFetchAll(SSdb *pSdb, ESdbType type, void *pIter, void **ppObj, ESdbStatus *status) ;
/**
* @brief Cancel a traversal
diff --git a/source/dnode/mnode/sdb/src/sdbHash.c b/source/dnode/mnode/sdb/src/sdbHash.c
index abf35b71a9..162da2bd0a 100644
--- a/source/dnode/mnode/sdb/src/sdbHash.c
+++ b/source/dnode/mnode/sdb/src/sdbHash.c
@@ -368,6 +368,34 @@ void *sdbFetch(SSdb *pSdb, ESdbType type, void *pIter, void **ppObj) {
return ppRow;
}
+void *sdbFetchAll(SSdb *pSdb, ESdbType type, void *pIter, void **ppObj, ESdbStatus *status) {
+ *ppObj = NULL;
+
+ SHashObj *hash = sdbGetHash(pSdb, type);
+ if (hash == NULL) return NULL;
+
+ TdThreadRwlock *pLock = &pSdb->locks[type];
+ taosThreadRwlockRdlock(pLock);
+
+ SSdbRow **ppRow = taosHashIterate(hash, pIter);
+ while (ppRow != NULL) {
+ SSdbRow *pRow = *ppRow;
+ if (pRow == NULL) {
+ ppRow = taosHashIterate(hash, ppRow);
+ continue;
+ }
+
+ atomic_add_fetch_32(&pRow->refCount, 1);
+ sdbPrintOper(pSdb, pRow, "fetch");
+ *ppObj = pRow->pObj;
+ *status = pRow->status;
+ break;
+ }
+ taosThreadRwlockUnlock(pLock);
+
+ return ppRow;
+}
+
void sdbCancelFetch(SSdb *pSdb, void *pIter) {
if (pIter == NULL) return;
SSdbRow *pRow = *(SSdbRow **)pIter;
diff --git a/source/dnode/vnode/CMakeLists.txt b/source/dnode/vnode/CMakeLists.txt
index 17445b7abe..890b8d08ab 100644
--- a/source/dnode/vnode/CMakeLists.txt
+++ b/source/dnode/vnode/CMakeLists.txt
@@ -35,7 +35,6 @@ target_sources(
"src/sma/smaTimeRange.c"
# tsdb
- # "src/tsdb/tsdbTDBImpl.c"
"src/tsdb/tsdbCommit.c"
"src/tsdb/tsdbCommit2.c"
"src/tsdb/tsdbFile.c"
@@ -45,17 +44,18 @@ target_sources(
"src/tsdb/tsdbMemTable2.c"
"src/tsdb/tsdbRead.c"
"src/tsdb/tsdbReadImpl.c"
- # "src/tsdb/tsdbSma.c"
"src/tsdb/tsdbWrite.c"
"src/tsdb/tsdbSnapshot.c"
# tq
"src/tq/tq.c"
"src/tq/tqExec.c"
- "src/tq/tqCommit.c"
+ "src/tq/tqMeta.c"
+ "src/tq/tqRead.c"
"src/tq/tqOffset.c"
"src/tq/tqPush.c"
- "src/tq/tqRead.c"
+ "src/tq/tqSink.c"
+ "src/tq/tqCommit.c"
)
target_include_directories(
vnode
diff --git a/source/dnode/vnode/inc/vnode.h b/source/dnode/vnode/inc/vnode.h
index 6be770cfa7..308f89736d 100644
--- a/source/dnode/vnode/inc/vnode.h
+++ b/source/dnode/vnode/inc/vnode.h
@@ -68,6 +68,7 @@ void vnodeGetInfo(SVnode *pVnode, const char **dbname, int32_t *vgId);
int32_t vnodeSnapshotReaderOpen(SVnode *pVnode, SVSnapshotReader **ppReader, int64_t sver, int64_t ever);
int32_t vnodeSnapshotReaderClose(SVSnapshotReader *pReader);
int32_t vnodeSnapshotRead(SVSnapshotReader *pReader, const void **ppData, uint32_t *nData);
+int32_t vnodeProcessCreateTSma(SVnode *pVnode, void *pCont, uint32_t contLen);
// meta
typedef struct SMeta SMeta; // todo: remove
@@ -78,13 +79,13 @@ void metaReaderInit(SMetaReader *pReader, SMeta *pMeta, int32_t flags);
void metaReaderClear(SMetaReader *pReader);
int32_t metaGetTableEntryByUid(SMetaReader *pReader, tb_uid_t uid);
int32_t metaReadNext(SMetaReader *pReader);
-const void *metaGetTableTagVal(SMetaEntry *pEntry, int16_t cid);
+const void *metaGetTableTagVal(SMetaEntry *pEntry, int16_t type, STagVal *tagVal);
typedef struct SMetaFltParam {
tb_uid_t suid;
int16_t cid;
int16_t type;
- char * val;
+ char *val;
bool reverse;
int (*filterFunc)(void *a, void *b, int16_t type);
@@ -118,7 +119,8 @@ tsdbReaderT tsdbQueryCacheLast(SVnode *pVnode, SQueryTableDataCond *pCond, STab
int32_t tsdbGetFileBlocksDistInfo(tsdbReaderT *pReader, STableBlockDistInfo *pTableBlockInfo);
bool isTsdbCacheLastRow(tsdbReaderT *pReader);
int32_t tsdbGetAllTableList(SMeta *pMeta, uint64_t uid, SArray *list);
-void * tsdbGetIdx(SMeta *pMeta);
+int32_t tsdbGetCtbIdList(SMeta *pMeta, int64_t suid, SArray *list);
+void *tsdbGetIdx(SMeta *pMeta);
int64_t tsdbGetNumOfRowsInMemTable(tsdbReaderT *pHandle);
bool tsdbNextDataBlock(tsdbReaderT pTsdbReadHandle);
@@ -172,7 +174,9 @@ struct SVnodeCfg {
bool isHeap;
bool isWeak;
int8_t isTsma;
+ int8_t isRsma;
int8_t hashMethod;
+ int8_t standby;
STsdbCfg tsdbCfg;
SWalCfg walCfg;
SSyncCfg syncCfg;
@@ -189,7 +193,7 @@ struct SMetaEntry {
int64_t version;
int8_t type;
tb_uid_t uid;
- char * name;
+ char *name;
union {
struct {
SSchemaWrapper schemaRow;
@@ -217,17 +221,17 @@ struct SMetaEntry {
struct SMetaReader {
int32_t flags;
- SMeta * pMeta;
+ SMeta *pMeta;
SDecoder coder;
SMetaEntry me;
- void * pBuf;
+ void *pBuf;
int32_t szBuf;
};
struct SMTbCursor {
- TBC * pDbc;
- void * pKey;
- void * pVal;
+ TBC *pDbc;
+ void *pKey;
+ void *pVal;
int32_t kLen;
int32_t vLen;
SMetaReader mr;
diff --git a/source/dnode/vnode/src/inc/meta.h b/source/dnode/vnode/src/inc/meta.h
index 9da603f894..52e576ee52 100644
--- a/source/dnode/vnode/src/inc/meta.h
+++ b/source/dnode/vnode/src/inc/meta.h
@@ -117,7 +117,7 @@ typedef struct {
} SSmaIdxKey;
// metaTable ==================
-int metaCreateTagIdxKey(tb_uid_t suid, int32_t cid, const void* pTagData, int8_t type, tb_uid_t uid,
+int metaCreateTagIdxKey(tb_uid_t suid, int32_t cid, const void* pTagData, int32_t nTagData, int8_t type, tb_uid_t uid,
STagIdxKey** ppTagIdxKey, int32_t* nTagIdxKey);
#ifndef META_REFACT
diff --git a/source/dnode/vnode/src/inc/sma.h b/source/dnode/vnode/src/inc/sma.h
index 0601df61e7..03dd2ea66c 100644
--- a/source/dnode/vnode/src/inc/sma.h
+++ b/source/dnode/vnode/src/inc/sma.h
@@ -219,7 +219,7 @@ static int32_t tdInitSmaEnv(SSma *pSma, int8_t smaType, const char *path, SDisk
void *tdFreeRSmaInfo(SRSmaInfo *pInfo);
int32_t tdProcessTSmaCreateImpl(SSma *pSma, int64_t version, const char *pMsg);
-int32_t tdUpdateExpiredWindowImpl(SSma *pSma, SSubmitReq *pMsg, int64_t version);
+int32_t tdUpdateExpiredWindowImpl(SSma *pSma, const SSubmitReq *pMsg, int64_t version);
// TODO: This is the basic params, and should wrap the params to a queryHandle.
int32_t tdGetTSmaDataImpl(SSma *pSma, char *pData, int64_t indexUid, TSKEY querySKey, int32_t nMaxResult);
@@ -227,4 +227,4 @@ int32_t tdGetTSmaDataImpl(SSma *pSma, char *pData, int64_t indexUid, TSKEY query
}
#endif
-#endif /*_TD_VNODE_SMA_H_*/
\ No newline at end of file
+#endif /*_TD_VNODE_SMA_H_*/
diff --git a/source/dnode/vnode/src/inc/tq.h b/source/dnode/vnode/src/inc/tq.h
index 34a7ff823a..7cd82b0ac3 100644
--- a/source/dnode/vnode/src/inc/tq.h
+++ b/source/dnode/vnode/src/inc/tq.h
@@ -66,33 +66,23 @@ struct STqReadHandle {
// tqPush
typedef struct {
- int64_t consumerId;
- int32_t epoch;
- int32_t skipLogNum;
- int64_t reqOffset;
- SRpcHandleInfo info;
- SRWLatch lock;
-} STqPushHandle;
-
-#if 0
-typedef struct {
- char subKey[TSDB_SUBSCRIBE_KEY_LEN];
+ // msg info
int64_t consumerId;
+ int64_t reqOffset;
+ int64_t processedVer;
int32_t epoch;
- int8_t subType;
- // int8_t withTbName;
- // int8_t withSchema;
- // int8_t withTag;
- char* qmsg;
- SHashObj* pDropTbUid;
- STqPushHandle pushHandle;
- // SRWLatch lock;
- SWalReadHandle* pWalReader;
- // task number should be the same with fetch thread
- STqReadHandle* pExecReader[5];
- qTaskInfo_t task[5];
-} STqExec;
-#endif
+ int32_t skipLogNum;
+ // rpc info
+ int64_t reqId;
+ SRpcHandleInfo rpcInfo;
+ tmr_h timerId;
+ int8_t tmrStopped;
+ // exec
+ int8_t inputStatus;
+ int8_t execStatus;
+ SStreamQ inputQ;
+ SRWLatch lock;
+} STqPushHandle;
// tqExec
@@ -154,28 +144,29 @@ typedef struct {
static STqMgmt tqMgmt = {0};
-// init once
-int tqInit();
-void tqCleanUp();
-
-// int32_t tEncodeSTqExec(SEncoder* pEncoder, const STqExec* pExec);
-// int32_t tDecodeSTqExec(SDecoder* pDecoder, STqExec* pExec);
-
-int32_t tEncodeSTqHandle(SEncoder* pEncoder, const STqHandle* pHandle);
-int32_t tDecodeSTqHandle(SDecoder* pDecoder, STqHandle* pHandle);
-
+// tqRead
int64_t tqFetchLog(STQ* pTq, STqHandle* pHandle, int64_t* fetchOffset, SWalHead** pHeadWithCkSum);
+// tqExec
int32_t tqDataExec(STQ* pTq, STqExecHandle* pExec, SSubmitReq* pReq, SMqDataBlkRsp* pRsp, int32_t workerId);
+int32_t tqSendPollRsp(STQ* pTq, const SRpcMsg* pMsg, const SMqPollReq* pReq, const SMqDataBlkRsp* pRsp);
+
+// tqMeta
+int32_t tqMetaOpen(STQ* pTq);
+int32_t tqMetaClose(STQ* pTq);
+int32_t tqMetaSaveHandle(STQ* pTq, const char* key, const STqHandle* pHandle);
+int32_t tqMetaDeleteHandle(STQ* pTq, const char* key);
+
+// tqSink
+void tqTableSink(SStreamTask* pTask, void* vnode, int64_t ver, void* data);
// tqOffset
-STqOffsetStore* STqOffsetOpen(STqOffsetCfg*);
-void STqOffsetClose(STqOffsetStore*);
-
-int64_t tqOffsetFetch(STqOffsetStore* pStore, const char* subscribeKey);
-int32_t tqOffsetCommit(STqOffsetStore* pStore, const char* subscribeKey, int64_t offset);
-int32_t tqOffsetPersist(STqOffsetStore* pStore, const char* subscribeKey);
-int32_t tqOffsetPersistAll(STqOffsetStore* pStore);
+STqOffsetStore* tqOffsetOpen(STqOffsetCfg*);
+void tqOffsetClose(STqOffsetStore*);
+int64_t tqOffsetFetch(STqOffsetStore* pStore, const char* subscribeKey);
+int32_t tqOffsetCommit(STqOffsetStore* pStore, const char* subscribeKey, int64_t offset);
+int32_t tqOffsetPersist(STqOffsetStore* pStore, const char* subscribeKey);
+int32_t tqOffsetPersistAll(STqOffsetStore* pStore);
#ifdef __cplusplus
}
diff --git a/source/dnode/vnode/src/inc/tsdb.h b/source/dnode/vnode/src/inc/tsdb.h
index 2e4ff6a4ab..a62b4c4409 100644
--- a/source/dnode/vnode/src/inc/tsdb.h
+++ b/source/dnode/vnode/src/inc/tsdb.h
@@ -32,14 +32,27 @@ extern "C" {
#define tsdbTrace(...) do { if (tsdbDebugFlag & DEBUG_TRACE) { taosPrintLog("TSDB ", DEBUG_TRACE, tsdbDebugFlag, __VA_ARGS__); }} while(0)
// clang-format on
+typedef struct TSDBROW TSDBROW;
+typedef struct TSDBKEY TSDBKEY;
+typedef struct SDelOp SDelOp;
+
+static int tsdbKeyCmprFn(const void *p1, const void *p2);
+
+// tsdbMemTable2.c ==============================================================================================
+typedef struct SMemTable SMemTable;
+
+int32_t tsdbMemTableCreate2(STsdb *pTsdb, SMemTable **ppMemTable);
+void tsdbMemTableDestroy2(SMemTable *pMemTable);
+
// tsdbMemTable ================
+typedef struct STsdbRow STsdbRow;
typedef struct STbData STbData;
typedef struct STsdbMemTable STsdbMemTable;
typedef struct SMergeInfo SMergeInfo;
typedef struct STable STable;
int tsdbMemTableCreate(STsdb *pTsdb, STsdbMemTable **ppMemTable);
-void tsdbMemTableDestroy(STsdb *pTsdb, STsdbMemTable *pMemTable);
+void tsdbMemTableDestroy(STsdbMemTable *pMemTable);
int tsdbLoadDataFromCache(STsdb *pTsdb, STable *pTable, SSkipListIterator *pIter, TSKEY maxKey, int maxRowsToRead,
SDataCols *pCols, TKEY *filterKeys, int nFilterKeys, bool keepDup, SMergeInfo *pMergeInfo);
@@ -845,6 +858,42 @@ static FORCE_INLINE int tsdbUnLockFS(STsdbFS *pFs) {
return 0;
}
+struct TSDBROW {
+ int64_t version;
+ STSRow2 tsRow;
+};
+
+struct TSDBKEY {
+ int64_t version;
+ TSKEY ts;
+};
+
+struct SDelOp {
+ int64_t version;
+ TSKEY sKey; // included
+ TSKEY eKey; // included
+ SDelOp *pNext;
+};
+
+static FORCE_INLINE int tsdbKeyCmprFn(const void *p1, const void *p2) {
+ TSDBKEY *pKey1 = (TSDBKEY *)p1;
+ TSDBKEY *pKey2 = (TSDBKEY *)p2;
+
+ if (pKey1->ts < pKey2->ts) {
+ return -1;
+ } else if (pKey1->ts > pKey2->ts) {
+ return 1;
+ }
+
+ if (pKey1->version < pKey2->version) {
+ return -1;
+ } else if (pKey1->version > pKey2->version) {
+ return 1;
+ }
+
+ return 0;
+}
+
#endif
#ifdef __cplusplus
diff --git a/source/dnode/vnode/src/inc/vnd.h b/source/dnode/vnode/src/inc/vnd.h
index eb3382ac4c..a5907cf991 100644
--- a/source/dnode/vnode/src/inc/vnd.h
+++ b/source/dnode/vnode/src/inc/vnd.h
@@ -81,9 +81,10 @@ int32_t vnodeSyncCommit(SVnode* pVnode);
int32_t vnodeAsyncCommit(SVnode* pVnode);
// vnodeSync.c
-int32_t vnodeSyncOpen(SVnode* pVnode, char* path);
-void vnodeSyncStart(SVnode* pVnode);
-void vnodeSyncClose(SVnode* pVnode);
+int32_t vnodeSyncOpen(SVnode* pVnode, char* path);
+void vnodeSyncStart(SVnode* pVnode);
+void vnodeSyncClose(SVnode* pVnode);
+void vnodeSyncAlter(SVnode* pVnode, SRpcMsg* pMsg);
#ifdef __cplusplus
}
diff --git a/source/dnode/vnode/src/inc/vnodeInt.h b/source/dnode/vnode/src/inc/vnodeInt.h
index d2c73316a1..d3b5f29aac 100644
--- a/source/dnode/vnode/src/inc/vnodeInt.h
+++ b/source/dnode/vnode/src/inc/vnodeInt.h
@@ -125,6 +125,8 @@ int32_t tsdbSnapshotReaderClose(STsdbSnapshotReader* pReader);
int32_t tsdbSnapshotRead(STsdbSnapshotReader* pReader, void** ppData, uint32_t* nData);
// tq
+int tqInit();
+void tqCleanUp();
STQ* tqOpen(const char* path, SVnode* pVnode, SWal* pWal);
void tqClose(STQ*);
int tqPushMsg(STQ*, void* msg, int32_t msgLen, tmsg_t msgType, int64_t ver);
@@ -145,11 +147,11 @@ int32_t tqProcessTaskRecoverRsp(STQ* pTq, SRpcMsg* pMsg);
int32_t smaOpen(SVnode* pVnode);
int32_t smaClose(SSma* pSma);
-int32_t tdUpdateExpireWindow(SSma* pSma, SSubmitReq* pMsg, int64_t version);
+int32_t tdUpdateExpireWindow(SSma* pSma, const SSubmitReq* pMsg, int64_t version);
int32_t tdProcessTSmaCreate(SSma* pSma, int64_t version, const char* msg);
int32_t tdProcessTSmaInsert(SSma* pSma, int64_t indexUid, const char* msg);
-int32_t tdProcessRSmaCreate(SVnode *pVnode, SVCreateStbReq* pReq);
+int32_t tdProcessRSmaCreate(SVnode* pVnode, SVCreateStbReq* pReq);
int32_t tdProcessRSmaSubmit(SSma* pSma, void* pMsg, int32_t inputType);
int32_t tdFetchTbUidList(SSma* pSma, STbUidStore** ppStore, tb_uid_t suid, tb_uid_t uid);
int32_t tdUpdateTbUidList(SSma* pSma, STbUidStore* pUidStore);
@@ -239,6 +241,8 @@ struct SVnode {
#define VND_RSMA1(vnd) ((vnd)->pSma->pRSmaTsdb1)
#define VND_RSMA2(vnd) ((vnd)->pSma->pRSmaTsdb2)
#define VND_RETENTIONS(vnd) (&(vnd)->config.tsdbCfg.retentions)
+#define VND_IS_RSMA(v) ((v)->config.isRsma == 1)
+#define VND_IS_TSMA(v) ((v)->config.isTsma == 1)
struct STbUidStore {
tb_uid_t suid;
@@ -271,11 +275,6 @@ struct SSma {
#define SMA_RSMA_TSDB1(s) ((s)->pRSmaTsdb1)
#define SMA_RSMA_TSDB2(s) ((s)->pRSmaTsdb2)
-static FORCE_INLINE bool vnodeIsRollup(SVnode* pVnode) {
- SRetention* pRetention = &(pVnode->config.tsdbCfg.retentions[0]);
- return (pRetention->freq > 0 && pRetention->keep > 0);
-}
-
// sma
void smaHandleRes(void* pVnode, int64_t smaId, const SArray* data);
diff --git a/source/dnode/vnode/src/meta/metaEntry.c b/source/dnode/vnode/src/meta/metaEntry.c
index be2ddfc32f..db99257ea7 100644
--- a/source/dnode/vnode/src/meta/metaEntry.c
+++ b/source/dnode/vnode/src/meta/metaEntry.c
@@ -30,7 +30,8 @@ int metaEncodeEntry(SEncoder *pCoder, const SMetaEntry *pME) {
if (tEncodeI64(pCoder, pME->ctbEntry.ctime) < 0) return -1;
if (tEncodeI32(pCoder, pME->ctbEntry.ttlDays) < 0) return -1;
if (tEncodeI64(pCoder, pME->ctbEntry.suid) < 0) return -1;
- if (tEncodeBinary(pCoder, pME->ctbEntry.pTags, kvRowLen(pME->ctbEntry.pTags)) < 0) return -1;
+ debugCheckTags((STag*)pME->ctbEntry.pTags); // TODO: remove after debug
+ if (tEncodeTag(pCoder, (const STag *)pME->ctbEntry.pTags) < 0) return -1;
} else if (pME->type == TSDB_NORMAL_TABLE) {
if (tEncodeI64(pCoder, pME->ntbEntry.ctime) < 0) return -1;
if (tEncodeI32(pCoder, pME->ntbEntry.ttlDays) < 0) return -1;
@@ -47,7 +48,6 @@ int metaEncodeEntry(SEncoder *pCoder, const SMetaEntry *pME) {
}
int metaDecodeEntry(SDecoder *pCoder, SMetaEntry *pME) {
- uint32_t len;
if (tStartDecode(pCoder) < 0) return -1;
if (tDecodeI64(pCoder, &pME->version) < 0) return -1;
@@ -62,7 +62,8 @@ int metaDecodeEntry(SDecoder *pCoder, SMetaEntry *pME) {
if (tDecodeI64(pCoder, &pME->ctbEntry.ctime) < 0) return -1;
if (tDecodeI32(pCoder, &pME->ctbEntry.ttlDays) < 0) return -1;
if (tDecodeI64(pCoder, &pME->ctbEntry.suid) < 0) return -1;
- if (tDecodeBinary(pCoder, &pME->ctbEntry.pTags, &len) < 0) return -1; // (TODO)
+ if (tDecodeTag(pCoder, (STag **)&pME->ctbEntry.pTags) < 0) return -1; // (TODO)
+ debugCheckTags((STag*)pME->ctbEntry.pTags); // TODO: remove after debug
} else if (pME->type == TSDB_NORMAL_TABLE) {
if (tDecodeI64(pCoder, &pME->ntbEntry.ctime) < 0) return -1;
if (tDecodeI32(pCoder, &pME->ntbEntry.ttlDays) < 0) return -1;
diff --git a/source/dnode/vnode/src/meta/metaQuery.c b/source/dnode/vnode/src/meta/metaQuery.c
index 8d9a1afefc..a57eb4e899 100644
--- a/source/dnode/vnode/src/meta/metaQuery.c
+++ b/source/dnode/vnode/src/meta/metaQuery.c
@@ -573,10 +573,23 @@ SArray *metaGetSmaTbUids(SMeta *pMeta) {
#endif
-const void *metaGetTableTagVal(SMetaEntry *pEntry, int16_t cid) {
+const void *metaGetTableTagVal(SMetaEntry *pEntry, int16_t type, STagVal *val) {
ASSERT(pEntry->type == TSDB_CHILD_TABLE);
- return tdGetKVRowValOfCol((const SKVRow)pEntry->ctbEntry.pTags, cid);
+ STag *tag = (STag *)pEntry->ctbEntry.pTags;
+ if (type == TSDB_DATA_TYPE_JSON){
+ if(tag->nTag == 0){
+ return NULL;
+ }
+ return tag;
+ }
+ bool find = tTagGet(tag, val);
+
+ if(!find){
+ return NULL;
+ }
+ return val;
}
+
typedef struct {
SMeta * pMeta;
TBC * pCur;
@@ -609,7 +622,13 @@ int32_t metaFilteTableIds(SMeta *pMeta, SMetaFltParam *param, SArray *pUids) {
STagIdxKey *pKey = NULL;
int32_t nKey = 0;
- ret = metaCreateTagIdxKey(pCursor->suid, pCursor->cid, param->val, pCursor->type,
+ int32_t nTagData = 0;
+ if(IS_VAR_DATA_TYPE(param->type)){
+ nTagData = strlen(param->val);
+ }else{
+ nTagData = tDataTypes[param->type].bytes;
+ }
+ ret = metaCreateTagIdxKey(pCursor->suid, pCursor->cid, param->val, nTagData, pCursor->type,
param->reverse ? INT64_MAX : INT64_MIN, &pKey, &nKey);
if (ret != 0) {
goto END;
@@ -651,4 +670,4 @@ END:
taosMemoryFree(pCursor);
return ret;
-}
+}
\ No newline at end of file
diff --git a/source/dnode/vnode/src/meta/metaTable.c b/source/dnode/vnode/src/meta/metaTable.c
index b588ea3203..9fef60b79f 100644
--- a/source/dnode/vnode/src/meta/metaTable.c
+++ b/source/dnode/vnode/src/meta/metaTable.c
@@ -49,9 +49,9 @@ int metaCreateSTable(SMeta *pMeta, int64_t version, SVCreateStbReq *pReq) {
int vLen = 0;
const void *pKey = NULL;
const void *pVal = NULL;
- void * pBuf = NULL;
+ void *pBuf = NULL;
int32_t szBuf = 0;
- void * p = NULL;
+ void *p = NULL;
SMetaReader mr = {0};
// validate req
@@ -105,7 +105,7 @@ int metaDropSTable(SMeta *pMeta, int64_t verison, SVDropStbReq *pReq) {
}
// drop all child tables
- TBC * pCtbIdxc = NULL;
+ TBC *pCtbIdxc = NULL;
SArray *pArray = taosArrayInit(8, sizeof(tb_uid_t));
tdbTbcOpen(pMeta->pCtbIdx, &pCtbIdxc, &pMeta->txn);
@@ -160,8 +160,8 @@ _exit:
int metaAlterSTable(SMeta *pMeta, int64_t version, SVCreateStbReq *pReq) {
SMetaEntry oStbEntry = {0};
SMetaEntry nStbEntry = {0};
- TBC * pUidIdxc = NULL;
- TBC * pTbDbc = NULL;
+ TBC *pUidIdxc = NULL;
+ TBC *pTbDbc = NULL;
const void *pData;
int nData;
int64_t oversion;
@@ -280,7 +280,7 @@ _err:
}
int metaDropTable(SMeta *pMeta, int64_t version, SVDropTbReq *pReq, SArray *tbUids) {
- void * pData = NULL;
+ void *pData = NULL;
int nData = 0;
int rc = 0;
tb_uid_t uid;
@@ -306,7 +306,7 @@ int metaDropTable(SMeta *pMeta, int64_t version, SVDropTbReq *pReq, SArray *tbUi
}
static int metaDropTableByUid(SMeta *pMeta, tb_uid_t uid, int *type) {
- void * pData = NULL;
+ void *pData = NULL;
int nData = 0;
int rc = 0;
int64_t version;
@@ -344,12 +344,12 @@ static int metaDropTableByUid(SMeta *pMeta, tb_uid_t uid, int *type) {
static int metaAlterTableColumn(SMeta *pMeta, int64_t version, SVAlterTbReq *pAlterTbReq, STableMetaRsp *pMetaRsp) {
void * pVal = NULL;
int nVal = 0;
- const void * pData = NULL;
+ const void *pData = NULL;
int nData = 0;
int ret = 0;
tb_uid_t uid;
int64_t oversion;
- SSchema * pColumn = NULL;
+ SSchema *pColumn = NULL;
SMetaEntry entry = {0};
SSchemaWrapper *pSchema;
int c;
@@ -499,7 +499,7 @@ _err:
static int metaUpdateTableTagVal(SMeta *pMeta, int64_t version, SVAlterTbReq *pAlterTbReq) {
SMetaEntry ctbEntry = {0};
SMetaEntry stbEntry = {0};
- void * pVal = NULL;
+ void *pVal = NULL;
int nVal = 0;
int ret;
int c;
@@ -530,7 +530,7 @@ static int metaUpdateTableTagVal(SMeta *pMeta, int64_t version, SVAlterTbReq *pA
oversion = *(int64_t *)pData;
// search table.db
- TBC * pTbDbc = NULL;
+ TBC *pTbDbc = NULL;
SDecoder dc1 = {0};
SDecoder dc2 = {0};
@@ -554,7 +554,7 @@ static int metaUpdateTableTagVal(SMeta *pMeta, int64_t version, SVAlterTbReq *pA
metaDecodeEntry(&dc2, &stbEntry);
SSchemaWrapper *pTagSchema = &stbEntry.stbEntry.schemaTag;
- SSchema * pColumn = NULL;
+ SSchema *pColumn = NULL;
int32_t iCol = 0;
for (;;) {
pColumn = NULL;
@@ -583,29 +583,39 @@ static int metaUpdateTableTagVal(SMeta *pMeta, int64_t version, SVAlterTbReq *pA
}
memcpy((void *)ctbEntry.ctbEntry.pTags, pAlterTbReq->pTagVal, pAlterTbReq->nTagVal);
} else {
- SKVRowBuilder kvrb = {0};
- const SKVRow pOldTag = (const SKVRow)ctbEntry.ctbEntry.pTags;
- SKVRow pNewTag = NULL;
-
- tdInitKVRowBuilder(&kvrb);
+ const STag *pOldTag = (const STag *)ctbEntry.ctbEntry.pTags;
+ STag *pNewTag = NULL;
+ SArray *pTagArray = taosArrayInit(pTagSchema->nCols, sizeof(STagVal));
+ if (!pTagArray) {
+ terrno = TSDB_CODE_OUT_OF_MEMORY;
+ goto _err;
+ }
for (int32_t i = 0; i < pTagSchema->nCols; i++) {
SSchema *pCol = &pTagSchema->pSchema[i];
if (iCol == i) {
- tdAddColToKVRow(&kvrb, pCol->colId, pAlterTbReq->pTagVal, pAlterTbReq->nTagVal);
+ STagVal val = {0};
+ val.type = pCol->type;
+ val.cid = pCol->colId;
+ if (IS_VAR_DATA_TYPE(pCol->type)) {
+ val.pData = pAlterTbReq->pTagVal;
+ val.nData = pAlterTbReq->nTagVal;
+ } else {
+ memcpy(&val.i64, pAlterTbReq->pTagVal, pAlterTbReq->nTagVal);
+ }
+ taosArrayPush(pTagArray, &val);
} else {
- void *p = tdGetKVRowValOfCol(pOldTag, pCol->colId);
- if (p) {
- if (IS_VAR_DATA_TYPE(pCol->type)) {
- tdAddColToKVRow(&kvrb, pCol->colId, p, varDataTLen(p));
- } else {
- tdAddColToKVRow(&kvrb, pCol->colId, p, pCol->bytes);
- }
+ STagVal val = {0};
+ if (tTagGet(pOldTag, &val)) {
+ taosArrayPush(pTagArray, &val);
}
}
}
-
- ctbEntry.ctbEntry.pTags = tdGetKVRowFromBuilder(&kvrb);
- tdDestroyKVRowBuilder(&kvrb);
+ if ((terrno = tTagNew(pTagArray, pTagSchema->version, false, &pNewTag)) < 0) {
+ taosArrayDestroy(pTagArray);
+ goto _err;
+ }
+ ctbEntry.ctbEntry.pTags = (uint8_t *)pNewTag;
+ taosArrayDestroy(pTagArray);
}
// save to table.db
@@ -659,8 +669,8 @@ int metaAlterTable(SMeta *pMeta, int64_t version, SVAlterTbReq *pReq, STableMeta
static int metaSaveToTbDb(SMeta *pMeta, const SMetaEntry *pME) {
STbDbKey tbDbKey;
- void * pKey = NULL;
- void * pVal = NULL;
+ void *pKey = NULL;
+ void *pVal = NULL;
int kLen = 0;
int vLen = 0;
SEncoder coder = {0};
@@ -741,17 +751,17 @@ static int metaUpdateCtbIdx(SMeta *pMeta, const SMetaEntry *pME) {
return tdbTbInsert(pMeta->pCtbIdx, &ctbIdxKey, sizeof(ctbIdxKey), NULL, 0, &pMeta->txn);
}
-int metaCreateTagIdxKey(tb_uid_t suid, int32_t cid, const void *pTagData, int8_t type, tb_uid_t uid,
+int metaCreateTagIdxKey(tb_uid_t suid, int32_t cid, const void *pTagData, int32_t nTagData, int8_t type, tb_uid_t uid,
STagIdxKey **ppTagIdxKey, int32_t *nTagIdxKey) {
- int32_t nTagData = 0;
+ // int32_t nTagData = 0;
- if (pTagData) {
- if (IS_VAR_DATA_TYPE(type)) {
- nTagData = varDataTLen(pTagData);
- } else {
- nTagData = tDataTypes[type].bytes;
- }
- }
+ // if (pTagData) {
+ // if (IS_VAR_DATA_TYPE(type)) {
+ // nTagData = varDataTLen(pTagData);
+ // } else {
+ // nTagData = tDataTypes[type].bytes;
+ // }
+ // }
*nTagIdxKey = sizeof(STagIdxKey) + nTagData + sizeof(tb_uid_t);
*ppTagIdxKey = (STagIdxKey *)taosMemoryMalloc(*nTagIdxKey);
@@ -775,14 +785,15 @@ static void metaDestroyTagIdxKey(STagIdxKey *pTagIdxKey) {
}
static int metaUpdateTagIdx(SMeta *pMeta, const SMetaEntry *pCtbEntry) {
- void * pData = NULL;
+ void *pData = NULL;
int nData = 0;
STbDbKey tbDbKey = {0};
SMetaEntry stbEntry = {0};
- STagIdxKey * pTagIdxKey = NULL;
+ STagIdxKey *pTagIdxKey = NULL;
int32_t nTagIdxKey;
const SSchema *pTagColumn; // = &stbEntry.stbEntry.schema.pSchema[0];
- const void * pTagData = NULL; //
+ const void *pTagData = NULL; //
+ int32_t nTagData = 0;
SDecoder dc = {0};
// get super table
@@ -795,7 +806,21 @@ static int metaUpdateTagIdx(SMeta *pMeta, const SMetaEntry *pCtbEntry) {
metaDecodeEntry(&dc, &stbEntry);
pTagColumn = &stbEntry.stbEntry.schemaTag.pSchema[0];
- pTagData = tdGetKVRowValOfCol((const SKVRow)pCtbEntry->ctbEntry.pTags, pTagColumn->colId);
+
+ STagVal tagVal = {.cid = pTagColumn->colId};
+ if (pTagColumn->type != TSDB_DATA_TYPE_JSON) {
+ tTagGet((const STag *)pCtbEntry->ctbEntry.pTags, &tagVal);
+ if (IS_VAR_DATA_TYPE(pTagColumn->type)) {
+ pTagData = tagVal.pData;
+ nTagData = (int32_t)tagVal.nData;
+ } else {
+ pTagData = &(tagVal.i64);
+ nTagData = tDataTypes[pTagColumn->type].bytes;
+ }
+ } else {
+ // pTagData = pCtbEntry->ctbEntry.pTags;
+ // nTagData = ((const STag *)pCtbEntry->ctbEntry.pTags)->len;
+ }
// update tag index
#ifdef USE_INVERTED_INDEX
@@ -810,8 +835,8 @@ static int metaUpdateTagIdx(SMeta *pMeta, const SMetaEntry *pCtbEntry) {
int ret = indexPut((SIndex *)pMeta->pTagIvtIdx, tmGroup, tuid);
indexMultiTermDestroy(tmGroup);
#else
- if (metaCreateTagIdxKey(pCtbEntry->ctbEntry.suid, pTagColumn->colId, pTagData, pTagColumn->type, pCtbEntry->uid,
- &pTagIdxKey, &nTagIdxKey) < 0) {
+ if (metaCreateTagIdxKey(pCtbEntry->ctbEntry.suid, pTagColumn->colId, pTagData, nTagData, pTagColumn->type,
+ pCtbEntry->uid, &pTagIdxKey, &nTagIdxKey) < 0) {
return -1;
}
tdbTbInsert(pMeta->pTagIdx, pTagIdxKey, nTagIdxKey, NULL, 0, &pMeta->txn);
@@ -824,7 +849,7 @@ static int metaUpdateTagIdx(SMeta *pMeta, const SMetaEntry *pCtbEntry) {
static int metaSaveToSkmDb(SMeta *pMeta, const SMetaEntry *pME) {
SEncoder coder = {0};
- void * pVal = NULL;
+ void *pVal = NULL;
int vLen = 0;
int rcode = 0;
SSkmDbKey skmDbKey = {0};
diff --git a/source/dnode/vnode/src/sma/sma.c b/source/dnode/vnode/src/sma/sma.c
index 0e7ce385a1..7a2b6a2757 100644
--- a/source/dnode/vnode/src/sma/sma.c
+++ b/source/dnode/vnode/src/sma/sma.c
@@ -15,7 +15,6 @@
#include "sma.h"
-
// TODO: Who is responsible for resource allocate and release?
int32_t tdProcessTSmaInsert(SSma* pSma, int64_t indexUid, const char* msg) {
int32_t code = TSDB_CODE_SUCCESS;
@@ -37,7 +36,7 @@ int32_t tdProcessTSmaCreate(SSma* pSma, int64_t version, const char* msg) {
return code;
}
-int32_t tdUpdateExpireWindow(SSma* pSma, SSubmitReq* pMsg, int64_t version) {
+int32_t tdUpdateExpireWindow(SSma* pSma, const SSubmitReq* pMsg, int64_t version) {
int32_t code = TSDB_CODE_SUCCESS;
if ((code = tdUpdateExpiredWindowImpl(pSma, pMsg, version)) < 0) {
smaWarn("vgId:%d update expired sma window failed since %s", SMA_VID(pSma), tstrerror(terrno));
diff --git a/source/dnode/vnode/src/sma/smaOpen.c b/source/dnode/vnode/src/sma/smaOpen.c
index 2a74fe78cb..dde6578054 100644
--- a/source/dnode/vnode/src/sma/smaOpen.c
+++ b/source/dnode/vnode/src/sma/smaOpen.c
@@ -104,7 +104,7 @@ int32_t smaOpen(SVnode *pVnode) {
taosThreadMutexInit(&pSma->mutex, NULL);
pSma->locked = false;
- if (vnodeIsRollup(pVnode)) {
+ if (VND_IS_RSMA(pVnode)) {
STsdbKeepCfg keepCfg = {0};
for (int i = 0; i < TSDB_RETENTION_MAX; ++i) {
if (i == TSDB_RETENTION_L0) {
diff --git a/source/dnode/vnode/src/sma/smaTimeRange.c b/source/dnode/vnode/src/sma/smaTimeRange.c
index f771e73c8a..f88afcaddf 100644
--- a/source/dnode/vnode/src/sma/smaTimeRange.c
+++ b/source/dnode/vnode/src/sma/smaTimeRange.c
@@ -932,7 +932,7 @@ static int32_t tdSetExpiredWindow(SSma *pSma, SHashObj *pItemsHash, int64_t inde
* @param msg SSubmitReq
* @return int32_t
*/
-int32_t tdUpdateExpiredWindowImpl(SSma *pSma, SSubmitReq *pMsg, int64_t version) {
+int32_t tdUpdateExpiredWindowImpl(SSma *pSma, const SSubmitReq *pMsg, int64_t version) {
// no time-range-sma, just return success
if (atomic_load_16(&SMA_TSMA_NUM(pSma)) <= 0) {
smaTrace("vgId:%d not update expire window since no tSma", SMA_VID(pSma));
diff --git a/source/dnode/vnode/src/tq/tq.c b/source/dnode/vnode/src/tq/tq.c
index 4bce829b10..310b59b2e8 100644
--- a/source/dnode/vnode/src/tq/tq.c
+++ b/source/dnode/vnode/src/tq/tq.c
@@ -14,7 +14,6 @@
*/
#include "tq.h"
-#include "tdbInt.h"
int32_t tqInit() {
int8_t old;
@@ -47,51 +46,6 @@ void tqCleanUp() {
}
}
-int tqExecKeyCompare(const void* pKey1, int32_t kLen1, const void* pKey2, int32_t kLen2) {
- return strcmp(pKey1, pKey2);
-}
-
-int32_t tqStoreHandle(STQ* pTq, const char* key, const STqHandle* pHandle) {
- int32_t code;
- int32_t vlen;
- tEncodeSize(tEncodeSTqHandle, pHandle, vlen, code);
- ASSERT(code == 0);
-
- void* buf = taosMemoryCalloc(1, vlen);
- if (buf == NULL) {
- ASSERT(0);
- }
-
- SEncoder encoder;
- tEncoderInit(&encoder, buf, vlen);
-
- if (tEncodeSTqHandle(&encoder, pHandle) < 0) {
- ASSERT(0);
- }
-
- TXN txn;
-
- if (tdbTxnOpen(&txn, 0, tdbDefaultMalloc, tdbDefaultFree, NULL, TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED) < 0) {
- ASSERT(0);
- }
-
- if (tdbBegin(pTq->pMetaStore, &txn) < 0) {
- ASSERT(0);
- }
-
- if (tdbTbUpsert(pTq->pExecStore, key, (int)strlen(key), buf, vlen, &txn) < 0) {
- ASSERT(0);
- }
-
- if (tdbCommit(pTq->pMetaStore, &txn) < 0) {
- ASSERT(0);
- }
-
- tEncoderClear(&encoder);
- taosMemoryFree(buf);
- return 0;
-}
-
STQ* tqOpen(const char* path, SVnode* pVnode, SWal* pWal) {
STQ* pTq = taosMemoryMalloc(sizeof(STQ));
if (pTq == NULL) {
@@ -108,60 +62,7 @@ STQ* tqOpen(const char* path, SVnode* pVnode, SWal* pWal) {
pTq->pushMgr = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), true, HASH_ENTRY_LOCK);
- if (tdbOpen(path, 16 * 1024, 1, &pTq->pMetaStore) < 0) {
- ASSERT(0);
- }
-
- if (tdbTbOpen("handles", -1, -1, tqExecKeyCompare, pTq->pMetaStore, &pTq->pExecStore) < 0) {
- ASSERT(0);
- }
-
- TXN txn;
-
- if (tdbTxnOpen(&txn, 0, tdbDefaultMalloc, tdbDefaultFree, NULL, 0) < 0) {
- ASSERT(0);
- }
-
- TBC* pCur;
- if (tdbTbcOpen(pTq->pExecStore, &pCur, &txn) < 0) {
- ASSERT(0);
- }
-
- void* pKey;
- int kLen;
- void* pVal;
- int vLen;
-
- tdbTbcMoveToFirst(pCur);
- SDecoder decoder;
-
- while (tdbTbcNext(pCur, &pKey, &kLen, &pVal, &vLen) == 0) {
- STqHandle handle;
- tDecoderInit(&decoder, (uint8_t*)pVal, vLen);
- tDecodeSTqHandle(&decoder, &handle);
- handle.pWalReader = walOpenReadHandle(pTq->pVnode->pWal);
- for (int32_t i = 0; i < 5; i++) {
- handle.execHandle.pExecReader[i] = tqInitSubmitMsgScanner(pTq->pVnode->pMeta);
- }
- if (handle.execHandle.subType == TOPIC_SUB_TYPE__COLUMN) {
- for (int32_t i = 0; i < 5; i++) {
- SReadHandle reader = {
- .reader = handle.execHandle.pExecReader[i],
- .meta = pTq->pVnode->pMeta,
- .pMsgCb = &pTq->pVnode->msgCb,
- };
- handle.execHandle.exec.execCol.task[i] =
- qCreateStreamExecTaskInfo(handle.execHandle.exec.execCol.qmsg, &reader);
- ASSERT(handle.execHandle.exec.execCol.task[i]);
- }
- } else {
- handle.execHandle.exec.execDb.pFilterOutTbUid =
- taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), false, HASH_NO_LOCK);
- }
- taosHashPut(pTq->handles, pKey, kLen, &handle, sizeof(STqHandle));
- }
-
- if (tdbTxnClose(&txn) < 0) {
+ if (tqMetaOpen(pTq) < 0) {
ASSERT(0);
}
@@ -174,181 +75,47 @@ void tqClose(STQ* pTq) {
taosHashCleanup(pTq->handles);
taosHashCleanup(pTq->pStreamTasks);
taosHashCleanup(pTq->pushMgr);
- tdbClose(pTq->pMetaStore);
+ tqMetaClose(pTq);
taosMemoryFree(pTq);
}
// TODO
}
-int32_t tEncodeSTqHandle(SEncoder* pEncoder, const STqHandle* pHandle) {
- if (tStartEncode(pEncoder) < 0) return -1;
- if (tEncodeCStr(pEncoder, pHandle->subKey) < 0) return -1;
- if (tEncodeI64(pEncoder, pHandle->consumerId) < 0) return -1;
- if (tEncodeI32(pEncoder, pHandle->epoch) < 0) return -1;
- if (tEncodeI8(pEncoder, pHandle->execHandle.subType) < 0) return -1;
- if (pHandle->execHandle.subType == TOPIC_SUB_TYPE__COLUMN) {
- if (tEncodeCStr(pEncoder, pHandle->execHandle.exec.execCol.qmsg) < 0) return -1;
- }
- tEndEncode(pEncoder);
- return pEncoder->pos;
-}
-
-int32_t tDecodeSTqHandle(SDecoder* pDecoder, STqHandle* pHandle) {
- if (tStartDecode(pDecoder) < 0) return -1;
- if (tDecodeCStrTo(pDecoder, pHandle->subKey) < 0) return -1;
- if (tDecodeI64(pDecoder, &pHandle->consumerId) < 0) return -1;
- if (tDecodeI32(pDecoder, &pHandle->epoch) < 0) return -1;
- if (tDecodeI8(pDecoder, &pHandle->execHandle.subType) < 0) return -1;
- if (pHandle->execHandle.subType == TOPIC_SUB_TYPE__COLUMN) {
- if (tDecodeCStrAlloc(pDecoder, &pHandle->execHandle.exec.execCol.qmsg) < 0) return -1;
- }
- tEndDecode(pDecoder);
- return 0;
-}
-
-int32_t tqUpdateTbUidList(STQ* pTq, const SArray* tbUidList, bool isAdd) {
- void* pIter = NULL;
- while (1) {
- pIter = taosHashIterate(pTq->handles, pIter);
- if (pIter == NULL) break;
- STqHandle* pExec = (STqHandle*)pIter;
- if (pExec->execHandle.subType == TOPIC_SUB_TYPE__COLUMN) {
- for (int32_t i = 0; i < 5; i++) {
- int32_t code = qUpdateQualifiedTableId(pExec->execHandle.exec.execCol.task[i], tbUidList, isAdd);
- ASSERT(code == 0);
- }
- } else if (pExec->execHandle.subType == TOPIC_SUB_TYPE__DB) {
- if (!isAdd) {
- int32_t sz = taosArrayGetSize(tbUidList);
- for (int32_t i = 0; i < sz; i++) {
- int64_t tbUid = *(int64_t*)taosArrayGet(tbUidList, i);
- taosHashPut(pExec->execHandle.exec.execDb.pFilterOutTbUid, &tbUid, sizeof(int64_t), NULL, 0);
- }
- }
- } else {
- // tq update id
- }
- }
- while (1) {
- pIter = taosHashIterate(pTq->pStreamTasks, pIter);
- if (pIter == NULL) break;
- SStreamTask* pTask = (SStreamTask*)pIter;
- if (pTask->inputType == STREAM_INPUT__DATA_SUBMIT) {
- int32_t code = qUpdateQualifiedTableId(pTask->exec.executor, tbUidList, isAdd);
- ASSERT(code == 0);
- }
- }
- return 0;
-}
-
-int32_t tqPushMsgNew(STQ* pTq, void* msg, int32_t msgLen, tmsg_t msgType, int64_t ver, SRpcHandleInfo handleInfo) {
- if (msgType != TDMT_VND_SUBMIT) return 0;
- void* pIter = NULL;
- STqHandle* pHandle = NULL;
- SSubmitReq* pReq = (SSubmitReq*)msg;
- int32_t workerId = 4;
- int64_t fetchOffset = ver;
-
- while (1) {
- pIter = taosHashIterate(pTq->pushMgr, pIter);
- if (pIter == NULL) break;
- pHandle = *(STqHandle**)pIter;
-
- taosWLockLatch(&pHandle->pushHandle.lock);
-
- /*SRpcHandleInfo* pInfo = atomic_load_ptr(&pHandle->pushHandle.pInfo);*/
- /*ASSERT(pInfo);*/
-
- SMqDataBlkRsp rsp = {0};
- rsp.reqOffset = pHandle->pushHandle.reqOffset;
- rsp.blockData = taosArrayInit(0, sizeof(void*));
- rsp.blockDataLen = taosArrayInit(0, sizeof(int32_t));
-
- if (msgType == TDMT_VND_SUBMIT) {
- tqDataExec(pTq, &pHandle->execHandle, pReq, &rsp, workerId);
- } else {
- // TODO
- ASSERT(0);
- }
-
- if (rsp.blockNum == 0) {
- taosWUnLockLatch(&pHandle->pushHandle.lock);
- continue;
- }
-
- ASSERT(taosArrayGetSize(rsp.blockData) == rsp.blockNum);
- ASSERT(taosArrayGetSize(rsp.blockDataLen) == rsp.blockNum);
-
- rsp.rspOffset = fetchOffset;
-
- int32_t tlen = sizeof(SMqRspHead) + tEncodeSMqDataBlkRsp(NULL, &rsp);
- void* buf = rpcMallocCont(tlen);
- if (buf == NULL) {
- // todo free
- return -1;
- }
-
- ((SMqRspHead*)buf)->mqMsgType = TMQ_MSG_TYPE__POLL_RSP;
- ((SMqRspHead*)buf)->epoch = pHandle->pushHandle.epoch;
- ((SMqRspHead*)buf)->consumerId = pHandle->pushHandle.consumerId;
-
- void* abuf = POINTER_SHIFT(buf, sizeof(SMqRspHead));
- tEncodeSMqDataBlkRsp(&abuf, &rsp);
-
- SRpcMsg resp = {
- .info = pHandle->pushHandle.info,
- .pCont = buf,
- .contLen = tlen,
- .code = 0,
- };
- tmsgSendRsp(&resp);
-
- /*atomic_store_ptr(&pHandle->pushHandle.pInfo, NULL);*/
- memset(&pHandle->pushHandle.info, 0, sizeof(SRpcHandleInfo));
- taosWUnLockLatch(&pHandle->pushHandle.lock);
-
- tqDebug("vg %d offset %ld from consumer %ld (epoch %d) send rsp, block num: %d, reqOffset: %ld, rspOffset: %ld",
- TD_VID(pTq->pVnode), fetchOffset, pHandle->pushHandle.consumerId, pHandle->pushHandle.epoch, rsp.blockNum,
- rsp.reqOffset, rsp.rspOffset);
-
- // TODO destroy
- taosArrayDestroy(rsp.blockData);
- taosArrayDestroy(rsp.blockDataLen);
+int32_t tqSendPollRsp(STQ* pTq, const SRpcMsg* pMsg, const SMqPollReq* pReq, const SMqDataBlkRsp* pRsp) {
+ int32_t tlen = sizeof(SMqRspHead) + tEncodeSMqDataBlkRsp(NULL, pRsp);
+ void* buf = rpcMallocCont(tlen);
+ if (buf == NULL) {
+ return -1;
}
- return 0;
-}
+ ((SMqRspHead*)buf)->mqMsgType = TMQ_MSG_TYPE__POLL_RSP;
+ ((SMqRspHead*)buf)->epoch = pReq->epoch;
+ ((SMqRspHead*)buf)->consumerId = pReq->consumerId;
-int tqPushMsg(STQ* pTq, void* msg, int32_t msgLen, tmsg_t msgType, int64_t ver) {
- if (msgType == TDMT_VND_SUBMIT) {
- if (taosHashGetSize(pTq->pStreamTasks) == 0) return 0;
+ void* abuf = POINTER_SHIFT(buf, sizeof(SMqRspHead));
+ tEncodeSMqDataBlkRsp(&abuf, pRsp);
- if (tdUpdateExpireWindow(pTq->pVnode->pSma, msg, ver) != 0) {
- // TODO handle sma error
- }
- void* data = taosMemoryMalloc(msgLen);
- if (data == NULL) {
- return -1;
- }
- memcpy(data, msg, msgLen);
+ SRpcMsg resp = {
+ .info = pMsg->info,
+ .pCont = buf,
+ .contLen = tlen,
+ .code = 0,
+ };
+ tmsgSendRsp(&resp);
- tqProcessStreamTrigger(pTq, data);
- }
+ tqDebug("vg %d from consumer %ld (epoch %d) send rsp, block num: %d, reqOffset: %ld, rspOffset: %ld",
+ TD_VID(pTq->pVnode), pReq->consumerId, pReq->epoch, pRsp->blockNum, pRsp->reqOffset, pRsp->rspOffset);
return 0;
}
-int tqCommit(STQ* pTq) {
- // do nothing
- return 0;
-}
-
int32_t tqProcessPollReq(STQ* pTq, SRpcMsg* pMsg, int32_t workerId) {
SMqPollReq* pReq = pMsg->pCont;
int64_t consumerId = pReq->consumerId;
- int64_t waitTime = pReq->timeout;
+ int64_t timeout = pReq->timeout;
int32_t reqEpoch = pReq->epoch;
int64_t fetchOffset;
+ int32_t code = 0;
// get offset to fetch message
if (pReq->currentOffset == TMQ_CONF__RESET_OFFSET__EARLIEAST) {
@@ -389,20 +156,18 @@ int32_t tqProcessPollReq(STQ* pTq, SRpcMsg* pMsg, int32_t workerId) {
}
if (pHandle->execHandle.subType == TOPIC_SUB_TYPE__COLUMN) {
rsp.withSchema = false;
-
rsp.withTag = false;
} else {
rsp.withSchema = true;
- rsp.blockSchema = taosArrayInit(0, sizeof(void*));
-
rsp.withTag = false;
+ rsp.blockSchema = taosArrayInit(0, sizeof(void*));
}
while (1) {
consumerEpoch = atomic_load_32(&pHandle->epoch);
if (consumerEpoch > reqEpoch) {
- tqDebug("tmq poll: consumer %ld (epoch %d) vg %d offset %ld, found new consumer epoch %d discard req epoch %d",
- consumerId, pReq->epoch, TD_VID(pTq->pVnode), fetchOffset, consumerEpoch, reqEpoch);
+ tqWarn("tmq poll: consumer %ld (epoch %d) vg %d offset %ld, found new consumer epoch %d, discard req epoch %d",
+ consumerId, pReq->epoch, TD_VID(pTq->pVnode), fetchOffset, consumerEpoch, reqEpoch);
break;
}
@@ -413,34 +178,15 @@ int32_t tqProcessPollReq(STQ* pTq, SRpcMsg* pMsg, int32_t workerId) {
SWalReadHead* pHead = &pHeadWithCkSum->head;
-#if 0
- // add to pushMgr
- taosWLockLatch(&pExec->pushHandle.lock);
-
- pExec->pushHandle.consumerId = consumerId;
- pExec->pushHandle.epoch = reqEpoch;
- pExec->pushHandle.reqOffset = rsp.reqOffset;
- pExec->pushHandle.skipLogNum = rsp.skipLogNum;
- pExec->pushHandle.handle = pMsg;
-
- taosWUnLockLatch(&pExec->pushHandle.lock);
-
- // TODO add timer
-
- // TODO: the pointer will always be valid?
- taosHashPut(pTq->pushMgr, &consumerId, sizeof(int64_t), &pExec, sizeof(void*));
- taosArrayDestroy(rsp.blockData);
- taosArrayDestroy(rsp.blockDataLen);
- return 0;
-#endif
-
tqDebug("tmq poll: consumer %ld (epoch %d) iter log, vg %d offset %ld msgType %d", consumerId, pReq->epoch,
TD_VID(pTq->pVnode), fetchOffset, pHead->msgType);
if (pHead->msgType == TDMT_VND_SUBMIT) {
SSubmitReq* pCont = (SSubmitReq*)&pHead->body;
- tqDataExec(pTq, &pHandle->execHandle, pCont, &rsp, workerId);
+ if (tqDataExec(pTq, &pHandle->execHandle, pCont, &rsp, workerId) < 0) {
+ /*ASSERT(0);*/
+ }
} else {
// TODO
ASSERT(0);
@@ -459,34 +205,16 @@ int32_t tqProcessPollReq(STQ* pTq, SRpcMsg* pMsg, int32_t workerId) {
ASSERT(taosArrayGetSize(rsp.blockData) == rsp.blockNum);
ASSERT(taosArrayGetSize(rsp.blockDataLen) == rsp.blockNum);
+ if (rsp.withSchema) {
+ ASSERT(taosArrayGetSize(rsp.blockSchema) == rsp.blockNum);
+ }
rsp.rspOffset = fetchOffset;
- int32_t tlen = sizeof(SMqRspHead) + tEncodeSMqDataBlkRsp(NULL, &rsp);
- void* buf = rpcMallocCont(tlen);
- if (buf == NULL) {
- pMsg->code = -1;
- return -1;
+ if (tqSendPollRsp(pTq, pMsg, pReq, &rsp) < 0) {
+ code = -1;
}
- ((SMqRspHead*)buf)->mqMsgType = TMQ_MSG_TYPE__POLL_RSP;
- ((SMqRspHead*)buf)->epoch = pReq->epoch;
- ((SMqRspHead*)buf)->consumerId = consumerId;
-
- void* abuf = POINTER_SHIFT(buf, sizeof(SMqRspHead));
- tEncodeSMqDataBlkRsp(&abuf, &rsp);
-
- SRpcMsg resp = {
- .info = pMsg->info,
- .pCont = buf,
- .contLen = tlen,
- .code = 0,
- };
- tmsgSendRsp(&resp);
-
- tqDebug("vg %d offset %ld from consumer %ld (epoch %d) send rsp, block num: %d, reqOffset: %ld, rspOffset: %ld",
- TD_VID(pTq->pVnode), fetchOffset, consumerId, pReq->epoch, rsp.blockNum, rsp.reqOffset, rsp.rspOffset);
-
// TODO wrap in destroy func
taosArrayDestroy(rsp.blockData);
taosArrayDestroy(rsp.blockDataLen);
@@ -499,7 +227,7 @@ int32_t tqProcessPollReq(STQ* pTq, SRpcMsg* pMsg, int32_t workerId) {
taosArrayDestroyP(rsp.blockTbName, (FDelete)taosMemoryFree);
}
- return 0;
+ return code;
}
int32_t tqProcessVgDeleteReq(STQ* pTq, char* msg, int32_t msgLen) {
@@ -508,24 +236,9 @@ int32_t tqProcessVgDeleteReq(STQ* pTq, char* msg, int32_t msgLen) {
int32_t code = taosHashRemove(pTq->handles, pReq->subKey, strlen(pReq->subKey));
ASSERT(code == 0);
- TXN txn;
-
- if (tdbTxnOpen(&txn, 0, tdbDefaultMalloc, tdbDefaultFree, NULL, TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED) < 0) {
+ if (tqMetaDeleteHandle(pTq, pReq->subKey) < 0) {
ASSERT(0);
}
-
- if (tdbBegin(pTq->pMetaStore, &txn) < 0) {
- ASSERT(0);
- }
-
- if (tdbTbDelete(pTq->pExecStore, pReq->subKey, (int)strlen(pReq->subKey), &txn) < 0) {
- /*ASSERT(0);*/
- }
-
- if (tdbCommit(pTq->pMetaStore, &txn) < 0) {
- ASSERT(0);
- }
-
return 0;
}
@@ -547,18 +260,14 @@ int32_t tqProcessVgChangeReq(STQ* pTq, char* msg, int32_t msgLen) {
pHandle->epoch = -1;
pHandle->execHandle.subType = req.subType;
- /*pExec->withTbName = req.withTbName;*/
- /*pExec->withSchema = req.withSchema;*/
- /*pExec->withTag = req.withTag;*/
-
- pHandle->execHandle.exec.execCol.qmsg = req.qmsg;
- req.qmsg = NULL;
pHandle->pWalReader = walOpenReadHandle(pTq->pVnode->pWal);
for (int32_t i = 0; i < 5; i++) {
pHandle->execHandle.pExecReader[i] = tqInitSubmitMsgScanner(pTq->pVnode->pMeta);
}
if (pHandle->execHandle.subType == TOPIC_SUB_TYPE__COLUMN) {
+ pHandle->execHandle.exec.execCol.qmsg = req.qmsg;
+ req.qmsg = NULL;
for (int32_t i = 0; i < 5; i++) {
SReadHandle handle = {
.reader = pHandle->execHandle.pExecReader[i],
@@ -573,6 +282,18 @@ int32_t tqProcessVgChangeReq(STQ* pTq, char* msg, int32_t msgLen) {
pHandle->execHandle.exec.execDb.pFilterOutTbUid =
taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), false, HASH_NO_LOCK);
} else if (pHandle->execHandle.subType == TOPIC_SUB_TYPE__TABLE) {
+ pHandle->execHandle.exec.execTb.suid = req.suid;
+ SArray* tbUidList = taosArrayInit(0, sizeof(int64_t));
+ tsdbGetCtbIdList(pTq->pVnode->pMeta, req.suid, tbUidList);
+ tqDebug("vg %d, tq try get suid: %ld", pTq->pVnode->config.vgId, req.suid);
+ for (int32_t i = 0; i < taosArrayGetSize(tbUidList); i++) {
+ int64_t tbUid = *(int64_t*)taosArrayGet(tbUidList, i);
+ tqDebug("vg %d, idx %d, uid: %ld", pTq->pVnode->config.vgId, i, tbUid);
+ }
+ for (int32_t i = 0; i < 5; i++) {
+ tqReadHandleSetTbUidList(pHandle->execHandle.pExecReader[i], tbUidList);
+ }
+ taosArrayDestroy(tbUidList);
}
taosHashPut(pTq->handles, req.subKey, strlen(req.subKey), pHandle, sizeof(STqHandle));
} else {
@@ -583,30 +304,12 @@ int32_t tqProcessVgChangeReq(STQ* pTq, char* msg, int32_t msgLen) {
atomic_add_fetch_32(&pHandle->epoch, 1);
}
- if (tqStoreHandle(pTq, req.subKey, pHandle) < 0) {
+ if (tqMetaSaveHandle(pTq, req.subKey, pHandle) < 0) {
// TODO
}
return 0;
}
-void tqTableSink(SStreamTask* pTask, void* vnode, int64_t ver, void* data) {
- const SArray* pRes = (const SArray*)data;
- SVnode* pVnode = (SVnode*)vnode;
-
- ASSERT(pTask->tbSink.pTSchema);
- SSubmitReq* pReq = tdBlockToSubmit(pRes, pTask->tbSink.pTSchema, true, pTask->tbSink.stbUid,
- pTask->tbSink.stbFullName, pVnode->config.vgId);
- /*tPrintFixedSchemaSubmitReq(pReq, pTask->tbSink.pTSchema);*/
- // build write msg
- SRpcMsg msg = {
- .msgType = TDMT_VND_SUBMIT,
- .pCont = pReq,
- .contLen = ntohl(pReq->length),
- };
-
- ASSERT(tmsgPutToQueue(&pVnode->msgCb, WRITE_QUEUE, &msg) == 0);
-}
-
int32_t tqProcessTaskDeploy(STQ* pTq, char* msg, int32_t msgLen) {
SStreamTask* pTask = taosMemoryCalloc(1, sizeof(SStreamTask));
if (pTask == NULL) {
@@ -697,9 +400,11 @@ int32_t tqProcessStreamTrigger(STQ* pTq, SSubmitReq* pReq) {
continue;
}
- streamDataSubmitRefInc(pSubmit);
- SStreamDataSubmit* pSubmitClone = taosAllocateQitem(sizeof(SStreamDataSubmit), DEF_QITEM);
- memcpy(pSubmitClone, pSubmit, sizeof(SStreamDataSubmit));
+ SStreamDataSubmit* pSubmitClone = streamSubmitRefClone(pSubmit);
+ if (pSubmitClone == NULL) {
+ atomic_store_8(&pTask->inputStatus, TASK_INPUT_STATUS__FAILED);
+ continue;
+ }
taosWriteQitem(pTask->inputQ, pSubmitClone);
int8_t execStatus = atomic_load_8(&pTask->status);
diff --git a/source/dnode/vnode/src/tq/tqCommit.c b/source/dnode/vnode/src/tq/tqCommit.c
index e31566f3fa..7b116bff2e 100644
--- a/source/dnode/vnode/src/tq/tqCommit.c
+++ b/source/dnode/vnode/src/tq/tqCommit.c
@@ -14,3 +14,8 @@
*/
#include "tq.h"
+
+int tqCommit(STQ* pTq) {
+ // do nothing
+ return 0;
+}
diff --git a/source/dnode/vnode/src/tq/tqMeta.c b/source/dnode/vnode/src/tq/tqMeta.c
index f2f48bbc8a..9447c4007b 100644
--- a/source/dnode/vnode/src/tq/tqMeta.c
+++ b/source/dnode/vnode/src/tq/tqMeta.c
@@ -12,3 +12,163 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
+#include "tdbInt.h"
+#include "tq.h"
+
+static int32_t tEncodeSTqHandle(SEncoder* pEncoder, const STqHandle* pHandle) {
+ if (tStartEncode(pEncoder) < 0) return -1;
+ if (tEncodeCStr(pEncoder, pHandle->subKey) < 0) return -1;
+ if (tEncodeI64(pEncoder, pHandle->consumerId) < 0) return -1;
+ if (tEncodeI32(pEncoder, pHandle->epoch) < 0) return -1;
+ if (tEncodeI8(pEncoder, pHandle->execHandle.subType) < 0) return -1;
+ if (pHandle->execHandle.subType == TOPIC_SUB_TYPE__COLUMN) {
+ if (tEncodeCStr(pEncoder, pHandle->execHandle.exec.execCol.qmsg) < 0) return -1;
+ }
+ tEndEncode(pEncoder);
+ return pEncoder->pos;
+}
+
+static int32_t tDecodeSTqHandle(SDecoder* pDecoder, STqHandle* pHandle) {
+ if (tStartDecode(pDecoder) < 0) return -1;
+ if (tDecodeCStrTo(pDecoder, pHandle->subKey) < 0) return -1;
+ if (tDecodeI64(pDecoder, &pHandle->consumerId) < 0) return -1;
+ if (tDecodeI32(pDecoder, &pHandle->epoch) < 0) return -1;
+ if (tDecodeI8(pDecoder, &pHandle->execHandle.subType) < 0) return -1;
+ if (pHandle->execHandle.subType == TOPIC_SUB_TYPE__COLUMN) {
+ if (tDecodeCStrAlloc(pDecoder, &pHandle->execHandle.exec.execCol.qmsg) < 0) return -1;
+ }
+ tEndDecode(pDecoder);
+ return 0;
+}
+
+int tqExecKeyCompare(const void* pKey1, int32_t kLen1, const void* pKey2, int32_t kLen2) {
+ return strcmp(pKey1, pKey2);
+}
+
+int32_t tqMetaOpen(STQ* pTq) {
+ if (tdbOpen(pTq->path, 16 * 1024, 1, &pTq->pMetaStore) < 0) {
+ ASSERT(0);
+ }
+
+ if (tdbTbOpen("handles", -1, -1, tqExecKeyCompare, pTq->pMetaStore, &pTq->pExecStore) < 0) {
+ ASSERT(0);
+ }
+
+ TXN txn;
+
+ if (tdbTxnOpen(&txn, 0, tdbDefaultMalloc, tdbDefaultFree, NULL, 0) < 0) {
+ ASSERT(0);
+ }
+
+ TBC* pCur;
+ if (tdbTbcOpen(pTq->pExecStore, &pCur, &txn) < 0) {
+ ASSERT(0);
+ }
+
+ void* pKey;
+ int kLen;
+ void* pVal;
+ int vLen;
+
+ tdbTbcMoveToFirst(pCur);
+ SDecoder decoder;
+
+ while (tdbTbcNext(pCur, &pKey, &kLen, &pVal, &vLen) == 0) {
+ STqHandle handle;
+ tDecoderInit(&decoder, (uint8_t*)pVal, vLen);
+ tDecodeSTqHandle(&decoder, &handle);
+ handle.pWalReader = walOpenReadHandle(pTq->pVnode->pWal);
+ for (int32_t i = 0; i < 5; i++) {
+ handle.execHandle.pExecReader[i] = tqInitSubmitMsgScanner(pTq->pVnode->pMeta);
+ }
+ if (handle.execHandle.subType == TOPIC_SUB_TYPE__COLUMN) {
+ for (int32_t i = 0; i < 5; i++) {
+ SReadHandle reader = {
+ .reader = handle.execHandle.pExecReader[i],
+ .meta = pTq->pVnode->pMeta,
+ .pMsgCb = &pTq->pVnode->msgCb,
+ };
+ handle.execHandle.exec.execCol.task[i] =
+ qCreateStreamExecTaskInfo(handle.execHandle.exec.execCol.qmsg, &reader);
+ ASSERT(handle.execHandle.exec.execCol.task[i]);
+ }
+ } else {
+ handle.execHandle.exec.execDb.pFilterOutTbUid =
+ taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), false, HASH_NO_LOCK);
+ }
+ taosHashPut(pTq->handles, pKey, kLen, &handle, sizeof(STqHandle));
+ }
+
+ if (tdbTxnClose(&txn) < 0) {
+ ASSERT(0);
+ }
+ return 0;
+}
+
+int32_t tqMetaClose(STQ* pTq) {
+ tdbClose(pTq->pMetaStore);
+ return 0;
+}
+
+int32_t tqMetaSaveHandle(STQ* pTq, const char* key, const STqHandle* pHandle) {
+ int32_t code;
+ int32_t vlen;
+ tEncodeSize(tEncodeSTqHandle, pHandle, vlen, code);
+ ASSERT(code == 0);
+
+ void* buf = taosMemoryCalloc(1, vlen);
+ if (buf == NULL) {
+ ASSERT(0);
+ }
+
+ SEncoder encoder;
+ tEncoderInit(&encoder, buf, vlen);
+
+ if (tEncodeSTqHandle(&encoder, pHandle) < 0) {
+ ASSERT(0);
+ }
+
+ TXN txn;
+
+ if (tdbTxnOpen(&txn, 0, tdbDefaultMalloc, tdbDefaultFree, NULL, TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED) < 0) {
+ ASSERT(0);
+ }
+
+ if (tdbBegin(pTq->pMetaStore, &txn) < 0) {
+ ASSERT(0);
+ }
+
+ if (tdbTbUpsert(pTq->pExecStore, key, (int)strlen(key), buf, vlen, &txn) < 0) {
+ ASSERT(0);
+ }
+
+ if (tdbCommit(pTq->pMetaStore, &txn) < 0) {
+ ASSERT(0);
+ }
+
+ tEncoderClear(&encoder);
+ taosMemoryFree(buf);
+ return 0;
+}
+
+int32_t tqMetaDeleteHandle(STQ* pTq, const char* key) {
+ TXN txn;
+
+ if (tdbTxnOpen(&txn, 0, tdbDefaultMalloc, tdbDefaultFree, NULL, TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED) < 0) {
+ ASSERT(0);
+ }
+
+ if (tdbBegin(pTq->pMetaStore, &txn) < 0) {
+ ASSERT(0);
+ }
+
+ if (tdbTbDelete(pTq->pExecStore, key, (int)strlen(key), &txn) < 0) {
+ /*ASSERT(0);*/
+ }
+
+ if (tdbCommit(pTq->pMetaStore, &txn) < 0) {
+ ASSERT(0);
+ }
+
+ return 0;
+}
diff --git a/source/dnode/vnode/src/tq/tqOffset.c b/source/dnode/vnode/src/tq/tqOffset.c
index 90f512611b..4d83a67579 100644
--- a/source/dnode/vnode/src/tq/tqOffset.c
+++ b/source/dnode/vnode/src/tq/tqOffset.c
@@ -30,7 +30,7 @@ struct STqOffsetStore {
SHashObj* pHash; // SHashObj
};
-STqOffsetStore* STqOffsetOpen(STqOffsetCfg* pCfg) {
+STqOffsetStore* tqOffsetOpen(STqOffsetCfg* pCfg) {
STqOffsetStore* pStore = taosMemoryMalloc(sizeof(STqOffsetStore));
if (pStore == NULL) {
return NULL;
diff --git a/source/dnode/vnode/src/tq/tqPush.c b/source/dnode/vnode/src/tq/tqPush.c
index f2f48bbc8a..26e9dfe2e2 100644
--- a/source/dnode/vnode/src/tq/tqPush.c
+++ b/source/dnode/vnode/src/tq/tqPush.c
@@ -12,3 +12,246 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
+
+#include "tq.h"
+
+void tqTmrRspFunc(void* param, void* tmrId) {
+ STqHandle* pHandle = (STqHandle*)param;
+ atomic_store_8(&pHandle->pushHandle.tmrStopped, 1);
+}
+
+int32_t tqExecFromInputQ(STQ* pTq, STqHandle* pHandle) {
+ SMqDataBlkRsp rsp = {0};
+ // 1. guard and set status executing
+ int8_t execStatus =
+ atomic_val_compare_exchange_8(&pHandle->pushHandle.execStatus, TASK_STATUS__IDLE, TASK_STATUS__EXECUTING);
+ if (execStatus == TASK_STATUS__IDLE) {
+ SStreamDataSubmit* pSubmit = NULL;
+ // 2. check processedVer
+ // 2.1. if not missed, get msg from queue
+ // 2.2. if missed, scan wal
+ pSubmit = streamQNextItem(&pHandle->pushHandle.inputQ);
+ while (pHandle->pushHandle.processedVer <= pSubmit->ver) {
+ // read from wal
+ }
+ while (pHandle->pushHandle.processedVer > pSubmit->ver + 1) {
+ streamQSetSuccess(&pHandle->pushHandle.inputQ);
+ streamDataSubmitRefDec(pSubmit);
+ pSubmit = streamQNextItem(&pHandle->pushHandle.inputQ);
+ if (pSubmit == NULL) break;
+ }
+ // 3. exec, after each success, update processed ver
+ // first run
+ while (pSubmit != NULL) {
+ ASSERT(pSubmit->ver == pHandle->pushHandle.processedVer + 1);
+ if (tqDataExec(pTq, &pHandle->execHandle, pSubmit->data, &rsp, 0) < 0) {
+ /*ASSERT(0);*/
+ }
+ // update processed
+ atomic_store_64(&pHandle->pushHandle.processedVer, pSubmit->ver);
+ streamQSetSuccess(&pHandle->pushHandle.inputQ);
+ streamDataSubmitRefDec(pSubmit);
+ if (rsp.blockNum > 0) {
+ goto SEND_RSP;
+ } else {
+ pSubmit = streamQNextItem(&pHandle->pushHandle.inputQ);
+ }
+ }
+ // set exec status closing
+ atomic_store_8(&pHandle->pushHandle.execStatus, TASK_STATUS__CLOSING);
+ // second run
+ while (pSubmit != NULL) {
+ ASSERT(pSubmit->ver == pHandle->pushHandle.processedVer + 1);
+ if (tqDataExec(pTq, &pHandle->execHandle, pSubmit->data, &rsp, 0) < 0) {
+ /*ASSERT(0);*/
+ }
+ // update processed
+ atomic_store_64(&pHandle->pushHandle.processedVer, pSubmit->ver);
+ streamQSetSuccess(&pHandle->pushHandle.inputQ);
+ streamDataSubmitRefDec(pSubmit);
+ if (rsp.blockNum > 0) {
+ goto SEND_RSP;
+ } else {
+ pSubmit = streamQNextItem(&pHandle->pushHandle.inputQ);
+ }
+ }
+ // set exec status idle
+ atomic_store_8(&pHandle->pushHandle.execStatus, TASK_STATUS__IDLE);
+ }
+SEND_RSP:
+ // 4. if get result
+ // 4.1 set exec input status blocked and exec status idle
+ atomic_store_8(&pHandle->pushHandle.execStatus, TASK_STATUS__IDLE);
+ // 4.2 rpc send
+ rsp.rspOffset = pHandle->pushHandle.processedVer;
+ /*if (tqSendPollRsp(pTq, pMsg, pReq, &rsp) < 0) {*/
+ /*return -1;*/
+ /*}*/
+ // 4.3 clear rpc info
+ memset(&pHandle->pushHandle.rpcInfo, 0, sizeof(SRpcHandleInfo));
+ return 0;
+}
+
+int32_t tqOpenPushHandle(STQ* pTq, STqHandle* pHandle) {
+ memset(&pHandle->pushHandle, 0, sizeof(STqPushHandle));
+ pHandle->pushHandle.inputQ.queue = taosOpenQueue();
+ pHandle->pushHandle.inputQ.qall = taosAllocateQall();
+ if (pHandle->pushHandle.inputQ.queue == NULL || pHandle->pushHandle.inputQ.qall == NULL) {
+ if (pHandle->pushHandle.inputQ.queue) {
+ taosCloseQueue(pHandle->pushHandle.inputQ.queue);
+ }
+ if (pHandle->pushHandle.inputQ.qall) {
+ taosFreeQall(pHandle->pushHandle.inputQ.qall);
+ }
+ return -1;
+ }
+ return 0;
+}
+
+int32_t tqPreparePush(STQ* pTq, STqHandle* pHandle, int64_t reqId, const SRpcHandleInfo* pInfo, int64_t processedVer,
+ int64_t timeout) {
+ memcpy(&pHandle->pushHandle.rpcInfo, pInfo, sizeof(SRpcHandleInfo));
+ atomic_store_64(&pHandle->pushHandle.reqId, reqId);
+ atomic_store_64(&pHandle->pushHandle.processedVer, processedVer);
+ atomic_store_8(&pHandle->pushHandle.inputStatus, TASK_INPUT_STATUS__NORMAL);
+ atomic_store_8(&pHandle->pushHandle.tmrStopped, 0);
+ taosTmrReset(tqTmrRspFunc, (int32_t)timeout, pHandle, tqMgmt.timer, &pHandle->pushHandle.timerId);
+ return 0;
+}
+
+int32_t tqEnqueue(STqHandle* pHandle, SStreamDataSubmit* pSubmit) {
+ int8_t inputStatus = atomic_load_8(&pHandle->pushHandle.inputStatus);
+ if (inputStatus == TASK_INPUT_STATUS__NORMAL) {
+ SStreamDataSubmit* pSubmitClone = streamSubmitRefClone(pSubmit);
+ if (pSubmitClone == NULL) {
+ return -1;
+ }
+ taosWriteQitem(pHandle->pushHandle.inputQ.queue, pSubmitClone);
+ return 0;
+ }
+ return -1;
+}
+
+int32_t tqSendExecReq(STQ* pTq, STqHandle* pHandle) {
+ //
+ return 0;
+}
+
+int32_t tqEnqueueAll(STQ* pTq, SSubmitReq* pReq) {
+ void* pIter = NULL;
+ SStreamDataSubmit* pSubmit = streamDataSubmitNew(pReq);
+ if (pSubmit == NULL) {
+ return -1;
+ }
+
+ while (1) {
+ pIter = taosHashIterate(pTq->handles, pIter);
+ if (pIter == NULL) break;
+ STqHandle* pHandle = (STqHandle*)pIter;
+ if (tqEnqueue(pHandle, pSubmit) < 0) {
+ continue;
+ }
+ int8_t execStatus = atomic_load_8(&pHandle->pushHandle.execStatus);
+ if (execStatus == TASK_STATUS__IDLE || execStatus == TASK_STATUS__CLOSING) {
+ tqSendExecReq(pTq, pHandle);
+ }
+ }
+
+ streamDataSubmitRefDec(pSubmit);
+
+ return 0;
+}
+
+int32_t tqPushMsgNew(STQ* pTq, void* msg, int32_t msgLen, tmsg_t msgType, int64_t ver, SRpcHandleInfo handleInfo) {
+ if (msgType != TDMT_VND_SUBMIT) return 0;
+ void* pIter = NULL;
+ STqHandle* pHandle = NULL;
+ SSubmitReq* pReq = (SSubmitReq*)msg;
+ int32_t workerId = 4;
+ int64_t fetchOffset = ver;
+
+ while (1) {
+ pIter = taosHashIterate(pTq->pushMgr, pIter);
+ if (pIter == NULL) break;
+ pHandle = *(STqHandle**)pIter;
+
+ taosWLockLatch(&pHandle->pushHandle.lock);
+
+ SMqDataBlkRsp rsp = {0};
+ rsp.reqOffset = pHandle->pushHandle.reqOffset;
+ rsp.blockData = taosArrayInit(0, sizeof(void*));
+ rsp.blockDataLen = taosArrayInit(0, sizeof(int32_t));
+
+ if (msgType == TDMT_VND_SUBMIT) {
+ tqDataExec(pTq, &pHandle->execHandle, pReq, &rsp, workerId);
+ } else {
+ // TODO
+ ASSERT(0);
+ }
+
+ if (rsp.blockNum == 0) {
+ taosWUnLockLatch(&pHandle->pushHandle.lock);
+ continue;
+ }
+
+ ASSERT(taosArrayGetSize(rsp.blockData) == rsp.blockNum);
+ ASSERT(taosArrayGetSize(rsp.blockDataLen) == rsp.blockNum);
+
+ rsp.rspOffset = fetchOffset;
+
+ int32_t tlen = sizeof(SMqRspHead) + tEncodeSMqDataBlkRsp(NULL, &rsp);
+ void* buf = rpcMallocCont(tlen);
+ if (buf == NULL) {
+ // todo free
+ return -1;
+ }
+
+ ((SMqRspHead*)buf)->mqMsgType = TMQ_MSG_TYPE__POLL_RSP;
+ ((SMqRspHead*)buf)->epoch = pHandle->pushHandle.epoch;
+ ((SMqRspHead*)buf)->consumerId = pHandle->pushHandle.consumerId;
+
+ void* abuf = POINTER_SHIFT(buf, sizeof(SMqRspHead));
+ tEncodeSMqDataBlkRsp(&abuf, &rsp);
+
+ SRpcMsg resp = {
+ .info = pHandle->pushHandle.rpcInfo,
+ .pCont = buf,
+ .contLen = tlen,
+ .code = 0,
+ };
+ tmsgSendRsp(&resp);
+
+ memset(&pHandle->pushHandle.rpcInfo, 0, sizeof(SRpcHandleInfo));
+ taosWUnLockLatch(&pHandle->pushHandle.lock);
+
+ tqDebug("vg %d offset %ld from consumer %ld (epoch %d) send rsp, block num: %d, reqOffset: %ld, rspOffset: %ld",
+ TD_VID(pTq->pVnode), fetchOffset, pHandle->pushHandle.consumerId, pHandle->pushHandle.epoch, rsp.blockNum,
+ rsp.reqOffset, rsp.rspOffset);
+
+ // TODO destroy
+ taosArrayDestroy(rsp.blockData);
+ taosArrayDestroy(rsp.blockDataLen);
+ }
+
+ return 0;
+}
+
+int tqPushMsg(STQ* pTq, void* msg, int32_t msgLen, tmsg_t msgType, int64_t ver) {
+ if (msgType == TDMT_VND_SUBMIT) {
+ if (taosHashGetSize(pTq->pStreamTasks) == 0) return 0;
+
+ if (tdUpdateExpireWindow(pTq->pVnode->pSma, msg, ver) != 0) {
+ // TODO handle sma error
+ }
+ void* data = taosMemoryMalloc(msgLen);
+ if (data == NULL) {
+ return -1;
+ }
+ memcpy(data, msg, msgLen);
+
+ tqProcessStreamTrigger(pTq, data);
+ }
+
+ return 0;
+}
+
diff --git a/source/dnode/vnode/src/tq/tqRead.c b/source/dnode/vnode/src/tq/tqRead.c
index 1f5d3b7f53..8909a00c72 100644
--- a/source/dnode/vnode/src/tq/tqRead.c
+++ b/source/dnode/vnode/src/tq/tqRead.c
@@ -298,3 +298,38 @@ int tqReadHandleRemoveTbUidList(STqReadHandle* pHandle, const SArray* tbUidList)
return 0;
}
+
+int32_t tqUpdateTbUidList(STQ* pTq, const SArray* tbUidList, bool isAdd) {
+ void* pIter = NULL;
+ while (1) {
+ pIter = taosHashIterate(pTq->handles, pIter);
+ if (pIter == NULL) break;
+ STqHandle* pExec = (STqHandle*)pIter;
+ if (pExec->execHandle.subType == TOPIC_SUB_TYPE__COLUMN) {
+ for (int32_t i = 0; i < 5; i++) {
+ int32_t code = qUpdateQualifiedTableId(pExec->execHandle.exec.execCol.task[i], tbUidList, isAdd);
+ ASSERT(code == 0);
+ }
+ } else if (pExec->execHandle.subType == TOPIC_SUB_TYPE__DB) {
+ if (!isAdd) {
+ int32_t sz = taosArrayGetSize(tbUidList);
+ for (int32_t i = 0; i < sz; i++) {
+ int64_t tbUid = *(int64_t*)taosArrayGet(tbUidList, i);
+ taosHashPut(pExec->execHandle.exec.execDb.pFilterOutTbUid, &tbUid, sizeof(int64_t), NULL, 0);
+ }
+ }
+ } else {
+ // tq update id
+ }
+ }
+ while (1) {
+ pIter = taosHashIterate(pTq->pStreamTasks, pIter);
+ if (pIter == NULL) break;
+ SStreamTask* pTask = (SStreamTask*)pIter;
+ if (pTask->inputType == STREAM_INPUT__DATA_SUBMIT) {
+ int32_t code = qUpdateQualifiedTableId(pTask->exec.executor, tbUidList, isAdd);
+ ASSERT(code == 0);
+ }
+ }
+ return 0;
+}
diff --git a/source/dnode/vnode/src/tq/tqSink.c b/source/dnode/vnode/src/tq/tqSink.c
new file mode 100644
index 0000000000..5c0bf971fb
--- /dev/null
+++ b/source/dnode/vnode/src/tq/tqSink.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019 TAOS Data, Inc.
+ *
+ * This program is free software: you can use, redistribute, and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3
+ * or later ("AGPL"), as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+#include "tq.h"
+
+void tqTableSink(SStreamTask* pTask, void* vnode, int64_t ver, void* data) {
+ const SArray* pRes = (const SArray*)data;
+ SVnode* pVnode = (SVnode*)vnode;
+
+ ASSERT(pTask->tbSink.pTSchema);
+ SSubmitReq* pReq = tdBlockToSubmit(pRes, pTask->tbSink.pTSchema, true, pTask->tbSink.stbUid,
+ pTask->tbSink.stbFullName, pVnode->config.vgId);
+ /*tPrintFixedSchemaSubmitReq(pReq, pTask->tbSink.pTSchema);*/
+ // build write msg
+ SRpcMsg msg = {
+ .msgType = TDMT_VND_SUBMIT,
+ .pCont = pReq,
+ .contLen = ntohl(pReq->length),
+ };
+
+ ASSERT(tmsgPutToQueue(&pVnode->msgCb, WRITE_QUEUE, &msg) == 0);
+}
diff --git a/source/dnode/vnode/src/tsdb/tsdbCommit.c b/source/dnode/vnode/src/tsdb/tsdbCommit.c
index 88d8ee9f92..0a85cb4638 100644
--- a/source/dnode/vnode/src/tsdb/tsdbCommit.c
+++ b/source/dnode/vnode/src/tsdb/tsdbCommit.c
@@ -238,7 +238,7 @@ static void tsdbStartCommit(STsdb *pRepo) {
static void tsdbEndCommit(STsdb *pTsdb, int eno) {
tsdbEndFSTxn(pTsdb);
- tsdbMemTableDestroy(pTsdb, pTsdb->imem);
+ tsdbMemTableDestroy(pTsdb->imem);
pTsdb->imem = NULL;
tsdbInfo("vgId:%d commit over, %s", REPO_ID(pTsdb), (eno == TSDB_CODE_SUCCESS) ? "succeed" : "failed");
}
diff --git a/source/dnode/vnode/src/tsdb/tsdbDelete.c b/source/dnode/vnode/src/tsdb/tsdbDelete.c
new file mode 100644
index 0000000000..6dea4a4e57
--- /dev/null
+++ b/source/dnode/vnode/src/tsdb/tsdbDelete.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2019 TAOS Data, Inc.
+ *
+ * This program is free software: you can use, redistribute, and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3
+ * or later ("AGPL"), as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
\ No newline at end of file
diff --git a/source/dnode/vnode/src/tsdb/tsdbMemTable.c b/source/dnode/vnode/src/tsdb/tsdbMemTable.c
index 9b9a431b50..350e723541 100644
--- a/source/dnode/vnode/src/tsdb/tsdbMemTable.c
+++ b/source/dnode/vnode/src/tsdb/tsdbMemTable.c
@@ -60,7 +60,7 @@ int tsdbMemTableCreate(STsdb *pTsdb, STsdbMemTable **ppMemTable) {
return 0;
}
-void tsdbMemTableDestroy(STsdb *pTsdb, STsdbMemTable *pMemTable) {
+void tsdbMemTableDestroy(STsdbMemTable *pMemTable) {
if (pMemTable) {
taosHashCleanup(pMemTable->pHashIdx);
SSkipListIterator *pIter = tSkipListCreateIter(pMemTable->pSlIdx);
@@ -142,69 +142,6 @@ int tsdbLoadDataFromCache(STsdb *pTsdb, STable *pTable, SSkipListIterator *pIter
} else {
fKey = tdGetKey(filterKeys[filterIter]);
}
-#if 0
- } else if (fKey > rowKey) {
- if (isRowDel) {
- pMergeInfo->rowsDeleteFailed++;
- } else {
- if (pMergeInfo->rowsInserted - pMergeInfo->rowsDeleteSucceed >= maxRowsToRead) break;
- if (pCols && pMergeInfo->nOperations >= pCols->maxPoints) break;
-
- pMergeInfo->rowsInserted++;
- pMergeInfo->nOperations++;
- pMergeInfo->keyFirst = TMIN(pMergeInfo->keyFirst, rowKey);
- pMergeInfo->keyLast = TMAX(pMergeInfo->keyLast, rowKey);
- tsdbAppendTableRowToCols(pTable, pCols, &pSchema, row);
- }
-
- tSkipListIterNext(pIter);
- row = tsdbNextIterRow(pIter);
- if (row == NULL || TD_ROW_KEY(row) > maxKey) {
- rowKey = INT64_MAX;
- isRowDel = false;
- } else {
- rowKey = TD_ROW_KEY(row);
- isRowDel = TD_ROW_IS_DELETED(row);
- }
- } else {
- if (isRowDel) {
- ASSERT(!keepDup);
- if (pCols && pMergeInfo->nOperations >= pCols->maxPoints) break;
- pMergeInfo->rowsDeleteSucceed++;
- pMergeInfo->nOperations++;
- tsdbAppendTableRowToCols(pTable, pCols, &pSchema, row);
- } else {
- if (keepDup) {
- if (pCols && pMergeInfo->nOperations >= pCols->maxPoints) break;
- pMergeInfo->rowsUpdated++;
- pMergeInfo->nOperations++;
- pMergeInfo->keyFirst = TMIN(pMergeInfo->keyFirst, rowKey);
- pMergeInfo->keyLast = TMAX(pMergeInfo->keyLast, rowKey);
- tsdbAppendTableRowToCols(pTable, pCols, &pSchema, row);
- } else {
- pMergeInfo->keyFirst = TMIN(pMergeInfo->keyFirst, fKey);
- pMergeInfo->keyLast = TMAX(pMergeInfo->keyLast, fKey);
- }
- }
-
- tSkipListIterNext(pIter);
- row = tsdbNextIterRow(pIter);
- if (row == NULL || TD_ROW_KEY(row) > maxKey) {
- rowKey = INT64_MAX;
- isRowDel = false;
- } else {
- rowKey = TD_ROW_KEY(row);
- isRowDel = TD_ROW_IS_DELETED(row);
- }
-
- filterIter++;
- if (filterIter >= nFilterKeys) {
- fKey = INT64_MAX;
- } else {
- fKey = tdGetKey(filterKeys[filterIter]);
- }
- }
-#endif
#if 1
} else if (fKey > rowKey) {
if (isRowDel) {
@@ -321,7 +258,7 @@ int tsdbInsertTableData(STsdb *pTsdb, SSubmitMsgIter *pMsgIter, SSubmitBlk *pBlo
terrno = TSDB_CODE_PAR_TABLE_NOT_EXIST;
return -1;
}
- if(pRsp->tblFName) strcat(pRsp->tblFName, mr.me.name);
+ if (pRsp->tblFName) strcat(pRsp->tblFName, mr.me.name);
if (mr.me.type == TSDB_NORMAL_TABLE) {
sverNew = mr.me.ntbEntry.schemaRow.version;
diff --git a/source/dnode/vnode/src/tsdb/tsdbMemTable2.c b/source/dnode/vnode/src/tsdb/tsdbMemTable2.c
index 025b2ab580..94c88a14ff 100644
--- a/source/dnode/vnode/src/tsdb/tsdbMemTable2.c
+++ b/source/dnode/vnode/src/tsdb/tsdbMemTable2.c
@@ -15,52 +15,308 @@
#include "tsdb.h"
-typedef struct SMemTable SMemTable;
-typedef struct SMemData SMemData;
-typedef struct SMemSkipList SMemSkipList;
-typedef struct SMemSkipListNode SMemSkipListNode;
-typedef struct SMemSkipListCurosr SMemSkipListCurosr;
-
-#define SL_MAX_LEVEL 5
-
-struct SMemTable {
- STsdb *pTsdb;
- TSKEY minKey;
- TSKEY maxKey;
- int64_t minVer;
- int64_t maxVer;
- int64_t nRows;
- int32_t nHash;
- int32_t nBucket;
- SMemData **pBuckets;
- SMemSkipListCurosr *pSlc;
-};
+typedef struct SMemData SMemData;
+typedef struct SMemSkipList SMemSkipList;
+typedef struct SMemSkipListNode SMemSkipListNode;
struct SMemSkipListNode {
int8_t level;
- SMemSkipListNode *forwards[1]; // Windows does not allow 0
+ SMemSkipListNode *forwards[0];
};
struct SMemSkipList {
- uint32_t seed;
- int8_t maxLevel;
- int8_t level;
- int32_t size;
- SMemSkipListNode pHead[1]; // Windows does not allow 0
+ uint32_t seed;
+ int32_t size;
+ int8_t maxLevel;
+ int8_t level;
+ SMemSkipListNode *pHead;
+ SMemSkipListNode *pTail;
};
struct SMemData {
- SMemData *pHashNext;
tb_uid_t suid;
tb_uid_t uid;
- TSKEY minKey;
- TSKEY maxKey;
- int64_t minVer;
- int64_t maxVer;
- int64_t nRows;
+ TSDBKEY minKey;
+ TSDBKEY maxKey;
+ SDelOp *delOpHead;
+ SDelOp *delOpTail;
SMemSkipList sl;
};
+struct SMemTable {
+ STsdb *pTsdb;
+ int32_t nRef;
+ TSDBKEY minKey;
+ TSDBKEY maxKey;
+ int64_t nRows;
+ SArray *pArray; // SArray
+};
+
+#define SL_NODE_SIZE(l) (sizeof(SMemSkipListNode) + sizeof(SMemSkipListNode *) * (l)*2)
+#define SL_NODE_HALF_SIZE(l) (sizeof(SMemSkipListNode) + sizeof(SMemSkipListNode *) * (l))
+#define SL_NODE_FORWARD(n, l) ((n)->forwards[l])
+#define SL_NODE_BACKWARD(n, l) ((n)->forwards[(n)->level + (l)])
+#define SL_NODE_DATA(n) (&SL_NODE_BACKWARD(n, (n)->level))
+
+#define SL_HEAD_FORWARD(sl, l) SL_NODE_FORWARD((sl)->pHead, l)
+#define SL_TAIL_BACKWARD(sl, l) SL_NODE_FORWARD((sl)->pTail, l)
+
+static int32_t tsdbGetOrCreateMemData(SMemTable *pMemTable, tb_uid_t suid, tb_uid_t uid, SMemData **ppMemData);
+static int memDataPCmprFn(const void *p1, const void *p2);
+static int32_t tPutTSDBRow(uint8_t *p, TSDBROW *pRow);
+static int32_t tGetTSDBRow(uint8_t *p, TSDBROW *pRow);
+static int8_t tsdbMemSkipListRandLevel(SMemSkipList *pSl);
+
+// SMemTable ==============================================
+int32_t tsdbMemTableCreate2(STsdb *pTsdb, SMemTable **ppMemTable) {
+ int32_t code = 0;
+ SMemTable *pMemTable = NULL;
+
+ pMemTable = (SMemTable *)taosMemoryCalloc(1, sizeof(*pMemTable));
+ if (pMemTable == NULL) {
+ code = TSDB_CODE_OUT_OF_MEMORY;
+ goto _err;
+ }
+ pMemTable->pTsdb = pTsdb;
+ pMemTable->nRef = 1;
+ pMemTable->minKey = (TSDBKEY){.version = INT64_MAX, .ts = TSKEY_MAX};
+ pMemTable->maxKey = (TSDBKEY){.version = -1, .ts = TSKEY_MIN};
+ pMemTable->nRows = 0;
+ pMemTable->pArray = taosArrayInit(512, sizeof(SMemData *));
+ if (pMemTable->pArray == NULL) {
+ taosMemoryFree(pMemTable);
+ code = TSDB_CODE_OUT_OF_MEMORY;
+ goto _err;
+ }
+
+ *ppMemTable = pMemTable;
+ return code;
+
+_err:
+ *ppMemTable = NULL;
+ return code;
+}
+
+void tsdbMemTableDestroy2(SMemTable *pMemTable) {
+ taosArrayDestroyEx(pMemTable->pArray, NULL /*TODO*/);
+ taosMemoryFree(pMemTable);
+}
+
+int32_t tsdbInsertTableData2(STsdb *pTsdb, int64_t version, SVSubmitBlk *pSubmitBlk) {
+ int32_t code = 0;
+ SMemTable *pMemTable = (SMemTable *)pTsdb->mem; // TODO
+ SMemData *pMemData;
+ TSDBROW row = {.version = version};
+
+ ASSERT(pMemTable);
+
+ {
+ // check if table exists (todo)
+ }
+
+ code = tsdbGetOrCreateMemData(pMemTable, pSubmitBlk->suid, pSubmitBlk->uid, &pMemData);
+ if (code) {
+ tsdbError("vgId:%d failed to create/get table data since %s", TD_VID(pTsdb->pVnode), tstrerror(code));
+ goto _err;
+ }
+
+ // do insert
+ int32_t nt;
+ uint8_t *pt;
+ int32_t n = 0;
+ uint8_t *p = pSubmitBlk->pData;
+ SVBufPool *pPool = pTsdb->pVnode->inUse;
+ int8_t level;
+ SMemSkipListNode *pNode;
+ while (n < pSubmitBlk->nData) {
+ nt = tGetTSRow(p + n, &row.tsRow);
+ n += nt;
+
+ ASSERT(n <= pSubmitBlk->nData);
+
+ // build the node
+ level = tsdbMemSkipListRandLevel(&pMemData->sl);
+ pNode = (SMemSkipListNode *)vnodeBufPoolMalloc(pPool, SL_NODE_SIZE(level) + nt + sizeof(version));
+ if (pNode == NULL) {
+ code = TSDB_CODE_OUT_OF_MEMORY;
+ goto _err;
+ }
+ pNode->level = level;
+ tPutTSDBRow((uint8_t *)SL_NODE_DATA(pNode), &row);
+
+ // put the node (todo)
+
+ // set info
+ if (tsdbKeyCmprFn(&row, &pMemData->minKey) < 0) pMemData->minKey = *(TSDBKEY *)&row;
+ if (tsdbKeyCmprFn(&row, &pMemData->maxKey) > 0) pMemData->maxKey = *(TSDBKEY *)&row;
+ }
+
+ if (tsdbKeyCmprFn(&pMemTable->minKey, &pMemData->minKey) < 0) pMemTable->minKey = pMemData->minKey;
+ if (tsdbKeyCmprFn(&pMemTable->maxKey, &pMemData->maxKey) > 0) pMemTable->maxKey = pMemData->maxKey;
+
+ return code;
+
+_err:
+ return code;
+}
+
+int32_t tsdbDeleteTableData2(STsdb *pTsdb, int64_t version, tb_uid_t suid, tb_uid_t uid, TSKEY sKey, TSKEY eKey) {
+ int32_t code = 0;
+ SMemTable *pMemTable = (SMemTable *)pTsdb->mem; // TODO
+ SMemData *pMemData;
+ SVBufPool *pPool = pTsdb->pVnode->inUse;
+
+ ASSERT(pMemTable);
+
+ {
+ // check if table exists (todo)
+ }
+
+ code = tsdbGetOrCreateMemData(pMemTable, suid, uid, &pMemData);
+ if (code) {
+ goto _err;
+ }
+
+ // do delete
+ SDelOp *pDelOp = (SDelOp *)vnodeBufPoolMalloc(pPool, sizeof(*pDelOp));
+ if (pDelOp == NULL) {
+ code = TSDB_CODE_OUT_OF_MEMORY;
+ goto _err;
+ }
+ pDelOp->version = version;
+ pDelOp->sKey = sKey;
+ pDelOp->eKey = eKey;
+ pDelOp->pNext = NULL;
+ if (pMemData->delOpHead == NULL) {
+ ASSERT(pMemData->delOpTail == NULL);
+ pMemData->delOpHead = pMemData->delOpTail = pDelOp;
+ } else {
+ pMemData->delOpTail->pNext = pDelOp;
+ pMemData->delOpTail = pDelOp;
+ }
+
+ {
+ // update the state of pMemTable, pMemData, last and lastrow (todo)
+ }
+
+ tsdbDebug("vgId:%d delete data from table suid:%" PRId64 " uid:%" PRId64 " sKey:%" PRId64 " eKey:%" PRId64
+ " since %s",
+ TD_VID(pTsdb->pVnode), suid, uid, sKey, eKey, tstrerror(code));
+ return code;
+
+_err:
+ tsdbError("vgId:%d failed to delete data from table suid:%" PRId64 " uid:%" PRId64 " sKey:%" PRId64 " eKey:%" PRId64
+ " since %s",
+ TD_VID(pTsdb->pVnode), suid, uid, sKey, eKey, tstrerror(code));
+ return code;
+}
+
+static int32_t tsdbGetOrCreateMemData(SMemTable *pMemTable, tb_uid_t suid, tb_uid_t uid, SMemData **ppMemData) {
+ int32_t code = 0;
+ int32_t idx = 0;
+ SMemData *pMemDataT = &(SMemData){.suid = suid, .uid = uid};
+ SMemData *pMemData = NULL;
+ SVBufPool *pPool = pMemTable->pTsdb->pVnode->inUse;
+ int8_t maxLevel = pMemTable->pTsdb->pVnode->config.tsdbCfg.slLevel;
+
+ // get
+ idx = taosArraySearchIdx(pMemTable->pArray, &pMemDataT, memDataPCmprFn, TD_GE);
+ if (idx >= 0) {
+ pMemData = (SMemData *)taosArrayGet(pMemTable->pArray, idx);
+ if (memDataPCmprFn(&pMemDataT, &pMemData) == 0) goto _exit;
+ }
+
+ // create
+ pMemData = vnodeBufPoolMalloc(pPool, sizeof(*pMemData) + SL_NODE_HALF_SIZE(maxLevel) * 2);
+ if (pMemData == NULL) {
+ code = TSDB_CODE_OUT_OF_MEMORY;
+ goto _err;
+ }
+ pMemData->suid = suid;
+ pMemData->uid = uid;
+ pMemData->minKey = (TSDBKEY){.version = INT64_MAX, .ts = TSKEY_MAX};
+ pMemData->maxKey = (TSDBKEY){.version = -1, .ts = TSKEY_MIN};
+ pMemData->delOpHead = pMemData->delOpTail = NULL;
+ pMemData->sl.seed = taosRand();
+ pMemData->sl.size = 0;
+ pMemData->sl.maxLevel = maxLevel;
+ pMemData->sl.level = 0;
+ pMemData->sl.pHead = (SMemSkipListNode *)&pMemData[1];
+ pMemData->sl.pTail = (SMemSkipListNode *)POINTER_SHIFT(pMemData->sl.pHead, SL_NODE_HALF_SIZE(maxLevel));
+
+ for (int8_t iLevel = 0; iLevel < pMemData->sl.maxLevel; iLevel++) {
+ SL_HEAD_FORWARD(&pMemData->sl, iLevel) = pMemData->sl.pTail;
+ SL_TAIL_BACKWARD(&pMemData->sl, iLevel) = pMemData->sl.pHead;
+ }
+
+ if (idx < 0) idx = 0;
+ if (taosArrayInsert(pMemTable->pArray, idx, &pMemData) == NULL) {
+ code = TSDB_CODE_OUT_OF_MEMORY;
+ goto _err;
+ }
+
+_exit:
+ *ppMemData = pMemData;
+ return code;
+
+_err:
+ *ppMemData = NULL;
+ return code;
+}
+
+static int memDataPCmprFn(const void *p1, const void *p2) {
+ SMemData *pMemData1 = *(SMemData **)p1;
+ SMemData *pMemData2 = *(SMemData **)p2;
+
+ if (pMemData1->suid < pMemData2->suid) {
+ return -1;
+ } else if (pMemData1->suid > pMemData2->suid) {
+ return 1;
+ }
+
+ if (pMemData1->uid < pMemData2->uid) {
+ return -1;
+ } else if (pMemData1->uid > pMemData2->uid) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int32_t tPutTSDBRow(uint8_t *p, TSDBROW *pRow) {
+ int32_t n = 0;
+
+ n += tPutI64(p ? p + n : p, pRow->version);
+ n += tPutTSRow(p ? p + n : p, &pRow->tsRow);
+
+ return n;
+}
+
+static int32_t tGetTSDBRow(uint8_t *p, TSDBROW *pRow) {
+ int32_t n = 0;
+
+ n += tGetI64(p + n, &pRow->version);
+ n += tGetTSRow(p + n, &pRow->tsRow);
+
+ return n;
+}
+
+static FORCE_INLINE int8_t tsdbMemSkipListRandLevel(SMemSkipList *pSl) {
+ int8_t level = 1;
+ int8_t tlevel = TMIN(pSl->maxLevel, pSl->level + 1);
+ const uint32_t factor = 4;
+
+ while ((taosRandR(&pSl->seed) % factor) == 0 && level < tlevel) {
+ level++;
+ }
+
+ return level;
+}
+
+#if 0 //====================================================================================
+
+#define SL_MAX_LEVEL 5
+
struct SMemSkipListCurosr {
SMemSkipList *pSl;
SMemSkipListNode *pNodes[SL_MAX_LEVEL];
@@ -74,12 +330,6 @@ typedef struct {
#define HASH_BUCKET(SUID, UID, NBUCKET) (TABS((SUID) + (UID)) % (NBUCKET))
-#define SL_NODE_SIZE(l) (sizeof(SMemSkipListNode) + sizeof(SMemSkipListNode *) * (l)*2)
-#define SL_NODE_HALF_SIZE(l) (sizeof(SMemSkipListNode) + sizeof(SMemSkipListNode *) * (l))
-#define SL_NODE_FORWARD(n, l) ((n)->forwards[l])
-#define SL_NODE_BACKWARD(n, l) ((n)->forwards[(n)->level + (l)])
-#define SL_NODE_DATA(n) (&SL_NODE_BACKWARD(n, (n)->level))
-
#define SL_HEAD_NODE(sl) ((sl)->pHead)
#define SL_TAIL_NODE(sl) ((SMemSkipListNode *)&SL_NODE_FORWARD(SL_HEAD_NODE(sl), (sl)->maxLevel))
#define SL_HEAD_NODE_FORWARD(n, l) SL_NODE_FORWARD(n, l)
@@ -99,50 +349,7 @@ static int32_t tsdbMemSkipListCursorMoveToNext(SMemSkipListCurosr *pSlc);
static int32_t tsdbMemSkipListCursorMoveToPrev(SMemSkipListCurosr *pSlc);
static SMemSkipListNode *tsdbMemSkipListNodeCreate(SVBufPool *pPool, SMemSkipList *pSl, const STsdbRow *pTRow);
-// SMemTable
-int32_t tsdbMemTableCreate2(STsdb *pTsdb, SMemTable **ppMemTb) {
- SMemTable *pMemTb = NULL;
-
- pMemTb = taosMemoryCalloc(1, sizeof(*pMemTb));
- if (pMemTb == NULL) {
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- return -1;
- }
-
- pMemTb->pTsdb = pTsdb;
- pMemTb->minKey = TSKEY_MAX;
- pMemTb->maxKey = TSKEY_MIN;
- pMemTb->minVer = -1;
- pMemTb->maxVer = -1;
- pMemTb->nRows = 0;
- pMemTb->nHash = 0;
- pMemTb->nBucket = 1024;
- pMemTb->pBuckets = taosMemoryCalloc(pMemTb->nBucket, sizeof(*pMemTb->pBuckets));
- if (pMemTb->pBuckets == NULL) {
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- taosMemoryFree(pMemTb);
- return -1;
- }
- if (tsdbMemSkipListCursorCreate(pTsdb->pVnode->config.tsdbCfg.slLevel, &pMemTb->pSlc) < 0) {
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- taosMemoryFree(pMemTb->pBuckets);
- taosMemoryFree(pMemTb);
- }
-
- *ppMemTb = pMemTb;
- return 0;
-}
-
-int32_t tsdbMemTableDestroy2(STsdb *pTsdb, SMemTable *pMemTb) {
- if (pMemTb) {
- // loop to destroy the contents (todo)
- tsdbMemSkipListCursorDestroy(pMemTb->pSlc);
- taosMemoryFree(pMemTb->pBuckets);
- taosMemoryFree(pMemTb);
- }
- return 0;
-}
-
+// SMemTable ========================
int32_t tsdbInsertData2(SMemTable *pMemTb, int64_t version, const SVSubmitBlk *pSubmitBlk) {
SMemData *pMemData;
STsdb *pTsdb = pMemTb->pTsdb;
@@ -253,18 +460,6 @@ int32_t tsdbInsertData2(SMemTable *pMemTb, int64_t version, const SVSubmitBlk *p
return 0;
}
-static FORCE_INLINE int8_t tsdbMemSkipListRandLevel(SMemSkipList *pSl) {
- int8_t level = 1;
- int8_t tlevel = TMIN(pSl->maxLevel, pSl->level + 1);
- const uint32_t factor = 4;
-
- while ((taosRandR(&pSl->seed) % factor) == 0 && level < tlevel) {
- level++;
- }
-
- return level;
-}
-
static FORCE_INLINE int32_t tsdbEncodeRow(SEncoder *pEncoder, const STsdbRow *pRow) {
if (tEncodeI64(pEncoder, pRow->version) < 0) return -1;
if (tEncodeBinary(pEncoder, (const uint8_t *)pRow->pRow, pRow->szRow) < 0) return -1;
@@ -377,4 +572,5 @@ static SMemSkipListNode *tsdbMemSkipListNodeCreate(SVBufPool *pPool, SMemSkipLis
}
return pNode;
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/source/dnode/vnode/src/tsdb/tsdbRead.c b/source/dnode/vnode/src/tsdb/tsdbRead.c
index 62125b6dc7..61daa0c9b3 100644
--- a/source/dnode/vnode/src/tsdb/tsdbRead.c
+++ b/source/dnode/vnode/src/tsdb/tsdbRead.c
@@ -13,8 +13,8 @@
* along with this program. If not, see .
*/
-#include "vnode.h"
#include "tsdb.h"
+#include "vnode.h"
#define EXTRA_BYTES 2
#define ASCENDING_TRAVERSE(o) (o == TSDB_ORDER_ASC)
@@ -327,13 +327,13 @@ static void setQueryTimewindow(STsdbReadHandle* pTsdbReadHandle, SQueryTableData
if (updateTs) {
tsdbDebug("%p update the query time window, old:%" PRId64 " - %" PRId64 ", new:%" PRId64 " - %" PRId64 ", %s",
- pTsdbReadHandle, pCond->twindows[tWinIdx].skey, pCond->twindows[tWinIdx].ekey, pTsdbReadHandle->window.skey,
- pTsdbReadHandle->window.ekey, pTsdbReadHandle->idStr);
+ pTsdbReadHandle, pCond->twindows[tWinIdx].skey, pCond->twindows[tWinIdx].ekey,
+ pTsdbReadHandle->window.skey, pTsdbReadHandle->window.ekey, pTsdbReadHandle->idStr);
}
}
static STsdb* getTsdbByRetentions(SVnode* pVnode, STsdbReadHandle* pReadHandle, TSKEY winSKey, SRetention* retentions) {
- if (vnodeIsRollup(pVnode)) {
+ if (VND_IS_RSMA(pVnode)) {
int level = 0;
int64_t now = taosGetTimestamp(pVnode->config.tsdbCfg.precision);
@@ -586,7 +586,8 @@ void tsdbResetReadHandle(tsdbReaderT queryHandle, SQueryTableDataCond* pCond, in
resetCheckInfo(pTsdbReadHandle);
}
-void tsdbResetQueryHandleForNewTable(tsdbReaderT queryHandle, SQueryTableDataCond* pCond, STableListInfo* tableList, int32_t tWinIdx) {
+void tsdbResetQueryHandleForNewTable(tsdbReaderT queryHandle, SQueryTableDataCond* pCond, STableListInfo* tableList,
+ int32_t tWinIdx) {
STsdbReadHandle* pTsdbReadHandle = queryHandle;
pTsdbReadHandle->order = pCond->order;
@@ -2845,6 +2846,22 @@ int32_t tsdbGetAllTableList(SMeta* pMeta, uint64_t uid, SArray* list) {
return TSDB_CODE_SUCCESS;
}
+int32_t tsdbGetCtbIdList(SMeta* pMeta, int64_t suid, SArray* list) {
+ SMCtbCursor* pCur = metaOpenCtbCursor(pMeta, suid);
+
+ while (1) {
+ tb_uid_t id = metaCtbCursorNext(pCur);
+ if (id == 0) {
+ break;
+ }
+
+ taosArrayPush(list, &id);
+ }
+
+ metaCloseCtbCursor(pCur);
+ return TSDB_CODE_SUCCESS;
+}
+
static void destroyHelper(void* param) {
if (param == NULL) {
return;
diff --git a/source/dnode/vnode/src/tsdb/tsdbSma.c b/source/dnode/vnode/src/tsdb/tsdbSma.c
deleted file mode 100644
index 45b17a0180..0000000000
--- a/source/dnode/vnode/src/tsdb/tsdbSma.c
+++ /dev/null
@@ -1,2203 +0,0 @@
-/*
- * Copyright (c) 2019 TAOS Data, Inc.
- *
- * This program is free software: you can use, redistribute, and/or modify
- * it under the terms of the GNU Affero General Public License, version 3
- * or later ("AGPL"), as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-#include "tsdbSma.h"
-#include "tsdb.h"
-
-static const char *TSDB_SMA_DNAME[] = {
- "", // TSDB_SMA_TYPE_BLOCK
- "tsma", // TSDB_SMA_TYPE_TIME_RANGE
- "rsma", // TSDB_SMA_TYPE_ROLLUP
-};
-
-#undef _TEST_SMA_PRINT_DEBUG_LOG_
-#define SMA_STORAGE_TSDB_DAYS 30
-#define SMA_STORAGE_TSDB_TIMES 10
-#define SMA_STORAGE_SPLIT_HOURS 24
-#define SMA_KEY_LEN 16 // TSKEY+groupId 8+8
-#define SMA_DROP_EXPIRED_TIME 10 // default is 10 seconds
-
-#define SMA_STATE_HASH_SLOT 4
-#define SMA_STATE_ITEM_HASH_SLOT 32
-
-#define SMA_TEST_INDEX_NAME "smaTestIndexName" // TODO: just for test
-#define SMA_TEST_INDEX_UID 2000000001 // TODO: just for test
-
-typedef struct SRSmaInfo SRSmaInfo;
-typedef enum {
- SMA_STORAGE_LEVEL_TSDB = 0, // use days of self-defined e.g. vnode${N}/tsdb/tsma/sma_index_uid/v2f200.tsma
- SMA_STORAGE_LEVEL_DFILESET = 1 // use days of TS data e.g. vnode${N}/tsdb/tsma/sma_index_uid/v2f1906.tsma
-} ESmaStorageLevel;
-
-typedef struct SPoolMem {
- int64_t size;
- struct SPoolMem *prev;
- struct SPoolMem *next;
-} SPoolMem;
-
-struct SSmaEnv {
- TdThreadRwlock lock;
- int8_t type;
- TXN txn;
- SPoolMem *pPool;
- SDiskID did;
- TDB *dbEnv; // TODO: If it's better to put it in smaIndex level?
- char *path; // relative path
- SSmaStat *pStat;
-};
-
-#define SMA_ENV_LOCK(env) ((env)->lock)
-#define SMA_ENV_TYPE(env) ((env)->type)
-#define SMA_ENV_DID(env) ((env)->did)
-#define SMA_ENV_ENV(env) ((env)->dbEnv)
-#define SMA_ENV_PATH(env) ((env)->path)
-#define SMA_ENV_STAT(env) ((env)->pStat)
-#define SMA_ENV_STAT_ITEMS(env) ((env)->pStat->smaStatItems)
-
-typedef struct {
- STsdb *pTsdb;
- SDBFile dFile;
- const SArray *pDataBlocks; // sma data
- int32_t interval; // interval with the precision of DB
-} STSmaWriteH;
-
-typedef struct {
- int32_t iter;
- int32_t fid;
-} SmaFsIter;
-
-typedef struct {
- STsdb *pTsdb;
- SDBFile dFile;
- int32_t interval; // interval with the precision of DB
- int32_t blockSize; // size of SMA block item
- int8_t storageLevel;
- int8_t days;
- SmaFsIter smaFsIter;
-} STSmaReadH;
-
-typedef struct {
- /**
- * @brief The field 'state' is here to demonstrate if one smaIndex is ready to provide service.
- * - TSDB_SMA_STAT_OK: 1) The sma calculation of history data is finished; 2) Or recevied information from
- * Streaming Module or TSDB local persistence.
- * - TSDB_SMA_STAT_EXPIRED: 1) If sma calculation of history TS data is not finished; 2) Or if the TSDB is open,
- * without information about its previous state.
- * - TSDB_SMA_STAT_DROPPED: 1)sma dropped
- * N.B. only applicable to tsma
- */
- int8_t state; // ETsdbSmaStat
- SHashObj *expiredWindows; // key: skey of time window, value: N/A
- STSma *pSma; // cache schema
-} SSmaStatItem;
-
-#define RSMA_TASK_INFO_HASH_SLOT 8
-struct SRSmaInfo {
- void *taskInfo[TSDB_RETENTION_L2]; // qTaskInfo_t
-};
-
-struct SSmaStat {
- union {
- SHashObj *smaStatItems; // key: indexUid, value: SSmaStatItem for tsma
- SHashObj *rsmaInfoHash; // key: stbUid, value: SRSmaInfo;
- };
- T_REF_DECLARE()
-};
-#define SMA_STAT_ITEMS(s) ((s)->smaStatItems)
-#define SMA_STAT_INFO_HASH(s) ((s)->rsmaInfoHash)
-
-static FORCE_INLINE void tsdbFreeTaskHandle(qTaskInfo_t *taskHandle) {
- // Note: free/kill may in RC
- qTaskInfo_t otaskHandle = atomic_load_ptr(taskHandle);
- if (otaskHandle && atomic_val_compare_exchange_ptr(taskHandle, otaskHandle, NULL)) {
- qDestroyTask(otaskHandle);
- }
-}
-
-static FORCE_INLINE void *tsdbFreeRSmaInfo(SRSmaInfo *pInfo) {
- for (int32_t i = 0; i < TSDB_RETENTION_MAX; ++i) {
- if (pInfo->taskInfo[i]) {
- tsdbFreeTaskHandle(pInfo->taskInfo[i]);
- }
- }
- return NULL;
-}
-
-// declaration of static functions
-
-// expired window
-static int32_t tsdbUpdateExpiredWindowImpl(STsdb *pTsdb, SSubmitReq *pMsg, int64_t version);
-static int32_t tsdbSetExpiredWindow(STsdb *pTsdb, SHashObj *pItemsHash, int64_t indexUid, int64_t winSKey,
- int64_t version);
-static int32_t tsdbInitSmaStat(SSmaStat **pSmaStat, int8_t smaType);
-static void *tsdbFreeSmaStatItem(SSmaStatItem *pSmaStatItem);
-static int32_t tsdbDestroySmaState(SSmaStat *pSmaStat, int8_t smaType);
-static SSmaEnv *tsdbNewSmaEnv(const STsdb *pTsdb, int8_t smaType, const char *path, SDiskID did);
-static int32_t tsdbInitSmaEnv(STsdb *pTsdb, int8_t smaType, const char *path, SDiskID did, SSmaEnv **pEnv);
-static int32_t tsdbResetExpiredWindow(STsdb *pTsdb, SSmaStat *pStat, int64_t indexUid, TSKEY skey);
-static int32_t tsdbRefSmaStat(STsdb *pTsdb, SSmaStat *pStat);
-static int32_t tsdbUnRefSmaStat(STsdb *pTsdb, SSmaStat *pStat);
-
-// read data
-// TODO: This is the basic params, and should wrap the params to a queryHandle.
-static int32_t tsdbGetTSmaDataImpl(STsdb *pTsdb, char *pData, int64_t indexUid, TSKEY querySKey, int32_t nMaxResult);
-
-// insert data
-static int32_t tsdbInitTSmaWriteH(STSmaWriteH *pSmaH, STsdb *pTsdb, const SArray *pDataBlocks, int64_t interval,
- int8_t intervalUnit);
-static void tsdbDestroyTSmaWriteH(STSmaWriteH *pSmaH);
-static int32_t tsdbInitTSmaReadH(STSmaReadH *pSmaH, STsdb *pTsdb, int64_t interval, int8_t intervalUnit);
-static int32_t tsdbGetSmaStorageLevel(int64_t interval, int8_t intervalUnit);
-static int32_t tsdbSetRSmaDataFile(STSmaWriteH *pSmaH, int32_t fid);
-static int32_t tsdbInsertTSmaBlocks(STSmaWriteH *pSmaH, void *smaKey, int32_t keyLen, void *pData, int32_t dataLen,
- TXN *txn);
-static int64_t tsdbGetIntervalByPrecision(int64_t interval, uint8_t intervalUnit, int8_t precision, bool adjusted);
-static int32_t tsdbGetTSmaDays(STsdb *pTsdb, int64_t interval, int32_t storageLevel);
-static int32_t tsdbSetTSmaDataFile(STSmaWriteH *pSmaH, int64_t indexUid, int32_t fid);
-static int32_t tsdbInitTSmaFile(STSmaReadH *pSmaH, int64_t indexUid, TSKEY skey);
-static bool tsdbSetAndOpenTSmaFile(STSmaReadH *pReadH, TSKEY *queryKey);
-static void tsdbGetSmaDir(int32_t vgId, ETsdbSmaType smaType, char dirName[]);
-static int32_t tsdbInsertTSmaDataImpl(STsdb *pTsdb, int64_t indexUid, const char *msg);
-static int32_t tsdbInsertRSmaDataImpl(STsdb *pTsdb, const char *msg);
-
-static FORCE_INLINE int32_t tsdbUidStorePut(STbUidStore *pStore, tb_uid_t suid, tb_uid_t *uid);
-static FORCE_INLINE int32_t tsdbUpdateTbUidListImpl(STsdb *pTsdb, tb_uid_t *suid, SArray *tbUids);
-static FORCE_INLINE int32_t tsdbExecuteRSmaImpl(STsdb *pTsdb, const void *pMsg, int32_t inputType,
- qTaskInfo_t *taskInfo, STSchema *pTSchema, tb_uid_t suid, tb_uid_t uid,
- int8_t level);
-// mgmt interface
-static int32_t tsdbDropTSmaDataImpl(STsdb *pTsdb, int64_t indexUid);
-
-// Pool Memory
-static SPoolMem *openPool();
-static void clearPool(SPoolMem *pPool);
-static void closePool(SPoolMem *pPool);
-static void *poolMalloc(void *arg, size_t size);
-static void poolFree(void *arg, void *ptr);
-
-static int tsdbSmaBeginCommit(SSmaEnv *pEnv);
-static int tsdbSmaEndCommit(SSmaEnv *pEnv);
-
-// implementation
-static FORCE_INLINE int16_t tsdbTSmaAdd(STsdb *pTsdb, int16_t n) {
- return atomic_add_fetch_16(&REPO_TSMA_NUM(pTsdb), n);
-}
-static FORCE_INLINE int16_t tsdbTSmaSub(STsdb *pTsdb, int16_t n) {
- return atomic_sub_fetch_16(&REPO_TSMA_NUM(pTsdb), n);
-}
-
-static FORCE_INLINE int32_t tsdbRLockSma(SSmaEnv *pEnv) {
- int code = taosThreadRwlockRdlock(&(pEnv->lock));
- if (code != 0) {
- terrno = TAOS_SYSTEM_ERROR(code);
- return -1;
- }
- return 0;
-}
-
-static FORCE_INLINE int32_t tsdbWLockSma(SSmaEnv *pEnv) {
- int code = taosThreadRwlockWrlock(&(pEnv->lock));
- if (code != 0) {
- terrno = TAOS_SYSTEM_ERROR(code);
- return -1;
- }
- return 0;
-}
-
-static FORCE_INLINE int32_t tsdbUnLockSma(SSmaEnv *pEnv) {
- int code = taosThreadRwlockUnlock(&(pEnv->lock));
- if (code != 0) {
- terrno = TAOS_SYSTEM_ERROR(code);
- return -1;
- }
- return 0;
-}
-
-static SPoolMem *openPool() {
- SPoolMem *pPool = (SPoolMem *)taosMemoryMalloc(sizeof(*pPool));
-
- pPool->prev = pPool->next = pPool;
- pPool->size = 0;
-
- return pPool;
-}
-
-static void clearPool(SPoolMem *pPool) {
- if (!pPool) return;
-
- SPoolMem *pMem;
-
- do {
- pMem = pPool->next;
-
- if (pMem == pPool) break;
-
- pMem->next->prev = pMem->prev;
- pMem->prev->next = pMem->next;
- pPool->size -= pMem->size;
-
- taosMemoryFree(pMem);
- } while (1);
-
- assert(pPool->size == 0);
-}
-
-static void closePool(SPoolMem *pPool) {
- if (pPool) {
- clearPool(pPool);
- taosMemoryFree(pPool);
- }
-}
-
-static void *poolMalloc(void *arg, size_t size) {
- void *ptr = NULL;
- SPoolMem *pPool = (SPoolMem *)arg;
- SPoolMem *pMem;
-
- pMem = (SPoolMem *)taosMemoryMalloc(sizeof(*pMem) + size);
- if (!pMem) {
- assert(0);
- }
-
- pMem->size = sizeof(*pMem) + size;
- pMem->next = pPool->next;
- pMem->prev = pPool;
-
- pPool->next->prev = pMem;
- pPool->next = pMem;
- pPool->size += pMem->size;
-
- ptr = (void *)(&pMem[1]);
- return ptr;
-}
-
-static void poolFree(void *arg, void *ptr) {
- SPoolMem *pPool = (SPoolMem *)arg;
- SPoolMem *pMem;
-
- pMem = &(((SPoolMem *)ptr)[-1]);
-
- pMem->next->prev = pMem->prev;
- pMem->prev->next = pMem->next;
- pPool->size -= pMem->size;
-
- taosMemoryFree(pMem);
-}
-
-int32_t tsdbInitSma(STsdb *pTsdb) {
- // tSma
- int32_t numOfTSma = taosArrayGetSize(metaGetSmaTbUids(REPO_META(pTsdb), false));
- if (numOfTSma > 0) {
- atomic_store_16(&REPO_TSMA_NUM(pTsdb), (int16_t)numOfTSma);
- }
- // TODO: rSma
- return TSDB_CODE_SUCCESS;
-}
-
-static FORCE_INLINE int8_t tsdbSmaStat(SSmaStatItem *pStatItem) {
- if (pStatItem) {
- return atomic_load_8(&pStatItem->state);
- }
- return TSDB_SMA_STAT_UNKNOWN;
-}
-
-static FORCE_INLINE bool tsdbSmaStatIsOK(SSmaStatItem *pStatItem, int8_t *state) {
- if (!pStatItem) {
- return false;
- }
-
- if (state) {
- *state = atomic_load_8(&pStatItem->state);
- return *state == TSDB_SMA_STAT_OK;
- }
- return atomic_load_8(&pStatItem->state) == TSDB_SMA_STAT_OK;
-}
-
-static FORCE_INLINE bool tsdbSmaStatIsExpired(SSmaStatItem *pStatItem) {
- return pStatItem ? (atomic_load_8(&pStatItem->state) & TSDB_SMA_STAT_EXPIRED) : true;
-}
-
-static FORCE_INLINE bool tsdbSmaStatIsDropped(SSmaStatItem *pStatItem) {
- return pStatItem ? (atomic_load_8(&pStatItem->state) & TSDB_SMA_STAT_DROPPED) : true;
-}
-
-static FORCE_INLINE void tsdbSmaStatSetOK(SSmaStatItem *pStatItem) {
- if (pStatItem) {
- atomic_store_8(&pStatItem->state, TSDB_SMA_STAT_OK);
- }
-}
-
-static FORCE_INLINE void tsdbSmaStatSetExpired(SSmaStatItem *pStatItem) {
- if (pStatItem) {
- atomic_or_fetch_8(&pStatItem->state, TSDB_SMA_STAT_EXPIRED);
- }
-}
-
-static FORCE_INLINE void tsdbSmaStatSetDropped(SSmaStatItem *pStatItem) {
- if (pStatItem) {
- atomic_or_fetch_8(&pStatItem->state, TSDB_SMA_STAT_DROPPED);
- }
-}
-
-static void tsdbGetSmaDir(int32_t vgId, ETsdbSmaType smaType, char dirName[]) {
- snprintf(dirName, TSDB_FILENAME_LEN, "vnode%svnode%d%s%s", TD_DIRSEP, vgId, TD_DIRSEP, TSDB_SMA_DNAME[smaType]);
-}
-
-static SSmaEnv *tsdbNewSmaEnv(const STsdb *pTsdb, int8_t smaType, const char *path, SDiskID did) {
- SSmaEnv *pEnv = NULL;
-
- pEnv = (SSmaEnv *)taosMemoryCalloc(1, sizeof(SSmaEnv));
- if (!pEnv) {
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- return NULL;
- }
-
- SMA_ENV_TYPE(pEnv) = smaType;
-
- int code = taosThreadRwlockInit(&(pEnv->lock), NULL);
- if (code) {
- terrno = TAOS_SYSTEM_ERROR(code);
- taosMemoryFree(pEnv);
- return NULL;
- }
-
- ASSERT(path && (strlen(path) > 0));
- SMA_ENV_PATH(pEnv) = strdup(path);
- if (!SMA_ENV_PATH(pEnv)) {
- tsdbFreeSmaEnv(pEnv);
- return NULL;
- }
-
- SMA_ENV_DID(pEnv) = did;
-
- if (tsdbInitSmaStat(&SMA_ENV_STAT(pEnv), smaType) != TSDB_CODE_SUCCESS) {
- tsdbFreeSmaEnv(pEnv);
- return NULL;
- }
-
- char aname[TSDB_FILENAME_LEN] = {0};
- tfsAbsoluteName(REPO_TFS(pTsdb), did, path, aname);
- if (tsdbOpenDBEnv(&pEnv->dbEnv, aname) != TSDB_CODE_SUCCESS) {
- tsdbFreeSmaEnv(pEnv);
- return NULL;
- }
-
- if (!(pEnv->pPool = openPool())) {
- tsdbFreeSmaEnv(pEnv);
- return NULL;
- }
-
- return pEnv;
-}
-
-static int32_t tsdbInitSmaEnv(STsdb *pTsdb, int8_t smaType, const char *path, SDiskID did, SSmaEnv **pEnv) {
- if (!pEnv) {
- terrno = TSDB_CODE_INVALID_PTR;
- return TSDB_CODE_FAILED;
- }
-
- if (!(*pEnv)) {
- if (!(*pEnv = tsdbNewSmaEnv(pTsdb, smaType, path, did))) {
- return TSDB_CODE_FAILED;
- }
- }
-
- return TSDB_CODE_SUCCESS;
-}
-
-/**
- * @brief Release resources allocated for its member fields, not including itself.
- *
- * @param pSmaEnv
- * @return int32_t
- */
-void tsdbDestroySmaEnv(SSmaEnv *pSmaEnv) {
- if (pSmaEnv) {
- tsdbDestroySmaState(pSmaEnv->pStat, SMA_ENV_TYPE(pSmaEnv));
- taosMemoryFreeClear(pSmaEnv->pStat);
- taosMemoryFreeClear(pSmaEnv->path);
- taosThreadRwlockDestroy(&(pSmaEnv->lock));
- tsdbCloseDBEnv(pSmaEnv->dbEnv);
- closePool(pSmaEnv->pPool);
- }
-}
-
-void *tsdbFreeSmaEnv(SSmaEnv *pSmaEnv) {
- tsdbDestroySmaEnv(pSmaEnv);
- taosMemoryFreeClear(pSmaEnv);
- return NULL;
-}
-
-static int32_t tsdbRefSmaStat(STsdb *pTsdb, SSmaStat *pStat) {
- if (!pStat) return 0;
-
- int ref = T_REF_INC(pStat);
- tsdbDebug("vgId:%d ref sma stat:%p, val:%d", REPO_ID(pTsdb), pStat, ref);
- return 0;
-}
-
-static int32_t tsdbUnRefSmaStat(STsdb *pTsdb, SSmaStat *pStat) {
- if (!pStat) return 0;
-
- int ref = T_REF_DEC(pStat);
- tsdbDebug("vgId:%d unref sma stat:%p, val:%d", REPO_ID(pTsdb), pStat, ref);
- return 0;
-}
-
-static int32_t tsdbInitSmaStat(SSmaStat **pSmaStat, int8_t smaType) {
- ASSERT(pSmaStat != NULL);
-
- if (*pSmaStat) { // no lock
- return TSDB_CODE_SUCCESS;
- }
-
- /**
- * 1. Lazy mode utilized when init SSmaStat to update expired window(or hungry mode when tsdbNew).
- * 2. Currently, there is mutex lock when init SSmaEnv, thus no need add lock on SSmaStat, and please add lock if
- * tsdbInitSmaStat invoked in other multithread environment later.
- */
- if (!(*pSmaStat)) {
- *pSmaStat = (SSmaStat *)taosMemoryCalloc(1, sizeof(SSmaStat));
- if (!(*pSmaStat)) {
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- return TSDB_CODE_FAILED;
- }
-
- if (smaType == TSDB_SMA_TYPE_ROLLUP) {
- SMA_STAT_INFO_HASH(*pSmaStat) = taosHashInit(
- RSMA_TASK_INFO_HASH_SLOT, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), true, HASH_ENTRY_LOCK);
-
- if (!SMA_STAT_INFO_HASH(*pSmaStat)) {
- taosMemoryFreeClear(*pSmaStat);
- return TSDB_CODE_FAILED;
- }
- } else if (smaType == TSDB_SMA_TYPE_TIME_RANGE) {
- SMA_STAT_ITEMS(*pSmaStat) =
- taosHashInit(SMA_STATE_HASH_SLOT, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_ENTRY_LOCK);
-
- if (!SMA_STAT_ITEMS(*pSmaStat)) {
- taosMemoryFreeClear(*pSmaStat);
- return TSDB_CODE_FAILED;
- }
- } else {
- ASSERT(0);
- }
- }
- return TSDB_CODE_SUCCESS;
-}
-
-static SSmaStatItem *tsdbNewSmaStatItem(int8_t state) {
- SSmaStatItem *pItem = NULL;
-
- pItem = (SSmaStatItem *)taosMemoryCalloc(1, sizeof(SSmaStatItem));
- if (pItem) {
- pItem->state = state;
- pItem->expiredWindows = taosHashInit(SMA_STATE_ITEM_HASH_SLOT, taosGetDefaultHashFunction(TSDB_DATA_TYPE_TIMESTAMP),
- true, HASH_ENTRY_LOCK);
- if (!pItem->expiredWindows) {
- taosMemoryFreeClear(pItem);
- }
- }
- return pItem;
-}
-
-static void *tsdbFreeSmaStatItem(SSmaStatItem *pSmaStatItem) {
- if (pSmaStatItem) {
- tdDestroyTSma(pSmaStatItem->pSma);
- taosMemoryFreeClear(pSmaStatItem->pSma);
- taosHashCleanup(pSmaStatItem->expiredWindows);
- taosMemoryFreeClear(pSmaStatItem);
- }
- return NULL;
-}
-
-/**
- * @brief Release resources allocated for its member fields, not including itself.
- *
- * @param pSmaStat
- * @return int32_t
- */
-int32_t tsdbDestroySmaState(SSmaStat *pSmaStat, int8_t smaType) {
- if (pSmaStat) {
- // TODO: use taosHashSetFreeFp when taosHashSetFreeFp is ready.
- if (smaType == TSDB_SMA_TYPE_TIME_RANGE) {
- void *item = taosHashIterate(SMA_STAT_ITEMS(pSmaStat), NULL);
- while (item) {
- SSmaStatItem *pItem = *(SSmaStatItem **)item;
- tsdbFreeSmaStatItem(pItem);
- item = taosHashIterate(SMA_STAT_ITEMS(pSmaStat), item);
- }
- taosHashCleanup(SMA_STAT_ITEMS(pSmaStat));
- } else if (smaType == TSDB_SMA_TYPE_ROLLUP) {
- void *infoHash = taosHashIterate(SMA_STAT_INFO_HASH(pSmaStat), NULL);
- while (infoHash) {
- SRSmaInfo *pInfoHash = *(SRSmaInfo **)infoHash;
- tsdbFreeRSmaInfo(pInfoHash);
- infoHash = taosHashIterate(SMA_STAT_INFO_HASH(pSmaStat), infoHash);
- }
- taosHashCleanup(SMA_STAT_INFO_HASH(pSmaStat));
- } else {
- ASSERT(0);
- }
- }
- return TSDB_CODE_SUCCESS;
-}
-
-static int32_t tsdbCheckAndInitSmaEnv(STsdb *pTsdb, int8_t smaType) {
- SSmaEnv *pEnv = NULL;
-
- // return if already init
- switch (smaType) {
- case TSDB_SMA_TYPE_TIME_RANGE:
- if ((pEnv = (SSmaEnv *)atomic_load_ptr(&REPO_TSMA_ENV(pTsdb)))) {
- return TSDB_CODE_SUCCESS;
- }
- break;
- case TSDB_SMA_TYPE_ROLLUP:
- if ((pEnv = (SSmaEnv *)atomic_load_ptr(&REPO_RSMA_ENV(pTsdb)))) {
- return TSDB_CODE_SUCCESS;
- }
- break;
- default:
- terrno = TSDB_CODE_INVALID_PARA;
- return TSDB_CODE_FAILED;
- }
-
- // init sma env
- tsdbLockRepo(pTsdb);
- pEnv = (smaType == TSDB_SMA_TYPE_TIME_RANGE) ? atomic_load_ptr(&REPO_TSMA_ENV(pTsdb))
- : atomic_load_ptr(&REPO_RSMA_ENV(pTsdb));
- if (!pEnv) {
- char rname[TSDB_FILENAME_LEN] = {0};
-
- SDiskID did = {0};
- tfsAllocDisk(REPO_TFS(pTsdb), TFS_PRIMARY_LEVEL, &did);
- if (did.level < 0 || did.id < 0) {
- tsdbUnlockRepo(pTsdb);
- return TSDB_CODE_FAILED;
- }
- tsdbGetSmaDir(REPO_ID(pTsdb), smaType, rname);
-
- if (tfsMkdirRecurAt(REPO_TFS(pTsdb), rname, did) != TSDB_CODE_SUCCESS) {
- tsdbUnlockRepo(pTsdb);
- return TSDB_CODE_FAILED;
- }
-
- if (tsdbInitSmaEnv(pTsdb, smaType, rname, did, &pEnv) != TSDB_CODE_SUCCESS) {
- tsdbUnlockRepo(pTsdb);
- return TSDB_CODE_FAILED;
- }
-
- (smaType == TSDB_SMA_TYPE_TIME_RANGE) ? atomic_store_ptr(&REPO_TSMA_ENV(pTsdb), pEnv)
- : atomic_store_ptr(&REPO_RSMA_ENV(pTsdb), pEnv);
- }
- tsdbUnlockRepo(pTsdb);
-
- return TSDB_CODE_SUCCESS;
-};
-
-static int32_t tsdbSetExpiredWindow(STsdb *pTsdb, SHashObj *pItemsHash, int64_t indexUid, int64_t winSKey,
- int64_t version) {
- SSmaStatItem *pItem = taosHashGet(pItemsHash, &indexUid, sizeof(indexUid));
- if (!pItem) {
- // TODO: use TSDB_SMA_STAT_EXPIRED and update by stream computing later
- pItem = tsdbNewSmaStatItem(TSDB_SMA_STAT_OK); // TODO use the real state
- if (!pItem) {
- // Response to stream computing: OOM
- // For query, if the indexUid not found, the TSDB should tell query module to query raw TS data.
- return TSDB_CODE_FAILED;
- }
-
- // cache smaMeta
- STSma *pSma = metaGetSmaInfoByIndex(REPO_META(pTsdb), indexUid, true);
- if (!pSma) {
- terrno = TSDB_CODE_TDB_NO_SMA_INDEX_IN_META;
- taosHashCleanup(pItem->expiredWindows);
- taosMemoryFree(pItem);
- tsdbWarn("vgId:%d update expired window failed for smaIndex %" PRIi64 " since %s", REPO_ID(pTsdb), indexUid,
- tstrerror(terrno));
- return TSDB_CODE_FAILED;
- }
- pItem->pSma = pSma;
-
- if (taosHashPut(pItemsHash, &indexUid, sizeof(indexUid), &pItem, sizeof(pItem)) != 0) {
- // If error occurs during put smaStatItem, free the resources of pItem
- taosHashCleanup(pItem->expiredWindows);
- taosMemoryFree(pItem);
- return TSDB_CODE_FAILED;
- }
- } else if (!(pItem = *(SSmaStatItem **)pItem)) {
- terrno = TSDB_CODE_INVALID_PTR;
- return TSDB_CODE_FAILED;
- }
-
- if (taosHashPut(pItem->expiredWindows, &winSKey, sizeof(TSKEY), &version, sizeof(version)) != 0) {
- // If error occurs during taosHashPut expired windows, remove the smaIndex from pTsdb->pSmaStat, thus TSDB would
- // tell query module to query raw TS data.
- // N.B.
- // 1) It is assumed to be extemely little probability event of fail to taosHashPut.
- // 2) This would solve the inconsistency to some extent, but not completely, unless we record all expired
- // windows failed to put into hash table.
- taosHashCleanup(pItem->expiredWindows);
- taosMemoryFreeClear(pItem->pSma);
- taosHashRemove(pItemsHash, &indexUid, sizeof(indexUid));
- tsdbWarn("vgId:%d smaIndex %" PRIi64 ", put skey %" PRIi64 " to expire window fail", REPO_ID(pTsdb), indexUid,
- winSKey);
- return TSDB_CODE_FAILED;
- }
-
- tsdbDebug("vgId:%d smaIndex %" PRIi64 ", put skey %" PRIi64 " to expire window succeed", REPO_ID(pTsdb), indexUid,
- winSKey);
- return TSDB_CODE_SUCCESS;
-}
-
-/**
- * @brief Update expired window according to msg from stream computing module.
- *
- * @param pTsdb
- * @param msg SSubmitReq
- * @return int32_t
- */
-int32_t tsdbUpdateExpiredWindowImpl(STsdb *pTsdb, SSubmitReq *pMsg, int64_t version) {
- // no time-range-sma, just return success
- if (atomic_load_16(&REPO_TSMA_NUM(pTsdb)) <= 0) {
- tsdbTrace("vgId:%d not update expire window since no tSma", REPO_ID(pTsdb));
- return TSDB_CODE_SUCCESS;
- }
-
- if (!REPO_META(pTsdb)) {
- terrno = TSDB_CODE_INVALID_PTR;
- return TSDB_CODE_FAILED;
- }
-
- if (tsdbCheckAndInitSmaEnv(pTsdb, TSDB_SMA_TYPE_TIME_RANGE) != TSDB_CODE_SUCCESS) {
- terrno = TSDB_CODE_TDB_INIT_FAILED;
- return TSDB_CODE_FAILED;
- }
-
- // Firstly, assume that tSma can only be created on super table/normal table.
- // getActiveTimeWindow
-
- SSmaEnv *pEnv = REPO_TSMA_ENV(pTsdb);
- SSmaStat *pStat = SMA_ENV_STAT(pEnv);
- SHashObj *pItemsHash = SMA_ENV_STAT_ITEMS(pEnv);
-
- TASSERT(pEnv && pStat && pItemsHash);
-
- // basic procedure
- // TODO: optimization
- tsdbRefSmaStat(pTsdb, pStat);
-
- SSubmitMsgIter msgIter = {0};
- SSubmitBlk *pBlock = NULL;
- SInterval interval = {0};
- TSKEY lastWinSKey = INT64_MIN;
-
- if (tInitSubmitMsgIter(pMsg, &msgIter) != TSDB_CODE_SUCCESS) {
- return TSDB_CODE_FAILED;
- }
-
- while (true) {
- tGetSubmitMsgNext(&msgIter, &pBlock);
- if (!pBlock) break;
-
- STSmaWrapper *pSW = NULL;
- STSma *pTSma = NULL;
-
- SSubmitBlkIter blkIter = {0};
- if (tInitSubmitBlkIter(&msgIter, pBlock, &blkIter) != TSDB_CODE_SUCCESS) {
- pSW = tdFreeTSmaWrapper(pSW);
- break;
- }
-
- while (true) {
- STSRow *row = tGetSubmitBlkNext(&blkIter);
- if (!row) {
- tdFreeTSmaWrapper(pSW);
- break;
- }
- if (!pSW || (pTSma->tableUid != pBlock->suid)) {
- if (pSW) {
- pSW = tdFreeTSmaWrapper(pSW);
- }
- if (!(pSW = metaGetSmaInfoByTable(REPO_META(pTsdb), pBlock->suid))) {
- break;
- }
- if ((pSW->number) <= 0 || !pSW->tSma) {
- pSW = tdFreeTSmaWrapper(pSW);
- break;
- }
-
- pTSma = pSW->tSma;
-
- interval.interval = pTSma->interval;
- interval.intervalUnit = pTSma->intervalUnit;
- interval.offset = pTSma->offset;
- interval.precision = REPO_CFG(pTsdb)->precision;
- interval.sliding = pTSma->sliding;
- interval.slidingUnit = pTSma->slidingUnit;
- }
-
- TSKEY winSKey = taosTimeTruncate(TD_ROW_KEY(row), &interval, interval.precision);
-
- if (lastWinSKey != winSKey) {
- lastWinSKey = winSKey;
- tsdbSetExpiredWindow(pTsdb, pItemsHash, pTSma->indexUid, winSKey, version);
- } else {
- tsdbDebug("vgId:%d smaIndex %" PRIi64 ", put skey %" PRIi64 " to expire window ignore as duplicated",
- REPO_ID(pTsdb), pTSma->indexUid, winSKey);
- }
- }
- }
-
- tsdbUnRefSmaStat(pTsdb, pStat);
-
- return TSDB_CODE_SUCCESS;
-}
-
-/**
- * @brief When sma data received from stream computing, make the relative expired window valid.
- *
- * @param pTsdb
- * @param pStat
- * @param indexUid
- * @param skey
- * @return int32_t
- */
-static int32_t tsdbResetExpiredWindow(STsdb *pTsdb, SSmaStat *pStat, int64_t indexUid, TSKEY skey) {
- SSmaStatItem *pItem = NULL;
-
- tsdbRefSmaStat(pTsdb, pStat);
-
- if (pStat && SMA_STAT_ITEMS(pStat)) {
- pItem = taosHashGet(SMA_STAT_ITEMS(pStat), &indexUid, sizeof(indexUid));
- }
- if ((pItem) && ((pItem = *(SSmaStatItem **)pItem))) {
- // pItem resides in hash buffer all the time unless drop sma index
- // TODO: multithread protect
- if (taosHashRemove(pItem->expiredWindows, &skey, sizeof(TSKEY)) != 0) {
- // error handling
- tsdbUnRefSmaStat(pTsdb, pStat);
- tsdbWarn("vgId:%d remove skey %" PRIi64 " from expired window for sma index %" PRIi64 " fail", REPO_ID(pTsdb),
- skey, indexUid);
- return TSDB_CODE_FAILED;
- }
- tsdbDebug("vgId:%d remove skey %" PRIi64 " from expired window for sma index %" PRIi64 " succeed", REPO_ID(pTsdb),
- skey, indexUid);
- // TODO: use a standalone interface to received state upate notification from stream computing module.
- /**
- * @brief state
- * - When SMA env init in TSDB, its status is TSDB_SMA_STAT_OK.
- * - In startup phase of stream computing module, it should notify the SMA env in TSDB to expired if needed(e.g.
- * when batch data caculation not finised)
- * - When TSDB_SMA_STAT_OK, the stream computing module should also notify that to the SMA env in TSDB.
- */
- pItem->state = TSDB_SMA_STAT_OK;
- } else {
- // error handling
- tsdbUnRefSmaStat(pTsdb, pStat);
- tsdbWarn("vgId:%d expired window %" PRIi64 " not exists for sma index %" PRIi64, REPO_ID(pTsdb), skey, indexUid);
- return TSDB_CODE_FAILED;
- }
-
- tsdbUnRefSmaStat(pTsdb, pStat);
- return TSDB_CODE_SUCCESS;
-}
-
-/**
- * @brief Judge the tSma storage level
- *
- * @param interval
- * @param intervalUnit
- * @return int32_t
- */
-static int32_t tsdbGetSmaStorageLevel(int64_t interval, int8_t intervalUnit) {
- // TODO: configurable for SMA_STORAGE_SPLIT_HOURS?
- switch (intervalUnit) {
- case TIME_UNIT_HOUR:
- if (interval < SMA_STORAGE_SPLIT_HOURS) {
- return SMA_STORAGE_LEVEL_DFILESET;
- }
- break;
- case TIME_UNIT_MINUTE:
- if (interval < 60 * SMA_STORAGE_SPLIT_HOURS) {
- return SMA_STORAGE_LEVEL_DFILESET;
- }
- break;
- case TIME_UNIT_SECOND:
- if (interval < 3600 * SMA_STORAGE_SPLIT_HOURS) {
- return SMA_STORAGE_LEVEL_DFILESET;
- }
- break;
- case TIME_UNIT_MILLISECOND:
- if (interval < 3600 * 1e3 * SMA_STORAGE_SPLIT_HOURS) {
- return SMA_STORAGE_LEVEL_DFILESET;
- }
- break;
- case TIME_UNIT_MICROSECOND:
- if (interval < 3600 * 1e6 * SMA_STORAGE_SPLIT_HOURS) {
- return SMA_STORAGE_LEVEL_DFILESET;
- }
- break;
- case TIME_UNIT_NANOSECOND:
- if (interval < 3600 * 1e9 * SMA_STORAGE_SPLIT_HOURS) {
- return SMA_STORAGE_LEVEL_DFILESET;
- }
- break;
- default:
- break;
- }
- return SMA_STORAGE_LEVEL_TSDB;
-}
-
-/**
- * @brief Insert TSma data blocks to DB File build by B+Tree
- *
- * @param pSmaH
- * @param smaKey tableUid-colId-skeyOfWindow(8-2-8)
- * @param keyLen
- * @param pData
- * @param dataLen
- * @return int32_t
- */
-static int32_t tsdbInsertTSmaBlocks(STSmaWriteH *pSmaH, void *smaKey, int32_t keyLen, void *pData, int32_t dataLen,
- TXN *txn) {
- SDBFile *pDBFile = &pSmaH->dFile;
-
- // TODO: insert tsma data blocks into B+Tree(TTB)
- if (tsdbSaveSmaToDB(pDBFile, smaKey, keyLen, pData, dataLen, txn) != 0) {
- tsdbWarn("vgId:%d insert tsma data blocks into %s: smaKey %" PRIx64 "-%" PRIx64 ", dataLen %" PRIu32 " fail",
- REPO_ID(pSmaH->pTsdb), pDBFile->path, *(int64_t *)smaKey, *(int64_t *)POINTER_SHIFT(smaKey, 8), dataLen);
- return TSDB_CODE_FAILED;
- }
- tsdbDebug("vgId:%d insert tsma data blocks into %s: smaKey %" PRIx64 "-%" PRIx64 ", dataLen %" PRIu32 " succeed",
- REPO_ID(pSmaH->pTsdb), pDBFile->path, *(int64_t *)smaKey, *(int64_t *)POINTER_SHIFT(smaKey, 8), dataLen);
-
-#ifdef _TEST_SMA_PRINT_DEBUG_LOG_
- uint32_t valueSize = 0;
- void *data = tsdbGetSmaDataByKey(pDBFile, smaKey, keyLen, &valueSize);
- ASSERT(data != NULL);
- for (uint32_t v = 0; v < valueSize; v += 8) {
- tsdbWarn("vgId:%d insert sma data val[%d] %" PRIi64, REPO_ID(pSmaH->pTsdb), v, *(int64_t *)POINTER_SHIFT(data, v));
- }
-#endif
- return TSDB_CODE_SUCCESS;
-}
-
-/**
- * @brief Approximate value for week/month/year.
- *
- * @param interval
- * @param intervalUnit
- * @param precision
- * @param adjusted Interval already adjusted according to DB precision
- * @return int64_t
- */
-static int64_t tsdbGetIntervalByPrecision(int64_t interval, uint8_t intervalUnit, int8_t precision, bool adjusted) {
- if (adjusted) {
- return interval;
- }
-
- switch (intervalUnit) {
- case TIME_UNIT_YEAR: // approximate value
- interval *= 365 * 86400 * 1e3;
- break;
- case TIME_UNIT_MONTH: // approximate value
- interval *= 30 * 86400 * 1e3;
- break;
- case TIME_UNIT_WEEK: // approximate value
- interval *= 7 * 86400 * 1e3;
- break;
- case TIME_UNIT_DAY: // the interval for tSma calculation must <= day
- interval *= 86400 * 1e3;
- break;
- case TIME_UNIT_HOUR:
- interval *= 3600 * 1e3;
- break;
- case TIME_UNIT_MINUTE:
- interval *= 60 * 1e3;
- break;
- case TIME_UNIT_SECOND:
- interval *= 1e3;
- break;
- default:
- break;
- }
-
- switch (precision) {
- case TSDB_TIME_PRECISION_MILLI:
- if (TIME_UNIT_MICROSECOND == intervalUnit) { // us
- return interval / 1e3;
- } else if (TIME_UNIT_NANOSECOND == intervalUnit) { // nano second
- return interval / 1e6;
- } else { // ms
- return interval;
- }
- break;
- case TSDB_TIME_PRECISION_MICRO:
- if (TIME_UNIT_MICROSECOND == intervalUnit) { // us
- return interval;
- } else if (TIME_UNIT_NANOSECOND == intervalUnit) { // ns
- return interval / 1e3;
- } else { // ms
- return interval * 1e3;
- }
- break;
- case TSDB_TIME_PRECISION_NANO:
- if (TIME_UNIT_MICROSECOND == intervalUnit) { // us
- return interval * 1e3;
- } else if (TIME_UNIT_NANOSECOND == intervalUnit) { // ns
- return interval;
- } else { // ms
- return interval * 1e6;
- }
- break;
- default: // ms
- if (TIME_UNIT_MICROSECOND == intervalUnit) { // us
- return interval / 1e3;
- } else if (TIME_UNIT_NANOSECOND == intervalUnit) { // ns
- return interval / 1e6;
- } else { // ms
- return interval;
- }
- break;
- }
- return interval;
-}
-
-static int32_t tsdbInitTSmaWriteH(STSmaWriteH *pSmaH, STsdb *pTsdb, const SArray *pDataBlocks, int64_t interval,
- int8_t intervalUnit) {
- pSmaH->pTsdb = pTsdb;
- pSmaH->interval = tsdbGetIntervalByPrecision(interval, intervalUnit, REPO_CFG(pTsdb)->precision, true);
- pSmaH->pDataBlocks = pDataBlocks;
- pSmaH->dFile.fid = TSDB_IVLD_FID;
- return TSDB_CODE_SUCCESS;
-}
-
-static void tsdbDestroyTSmaWriteH(STSmaWriteH *pSmaH) {
- if (pSmaH) {
- tsdbCloseDBF(&pSmaH->dFile);
- }
-}
-
-static int32_t tsdbSetTSmaDataFile(STSmaWriteH *pSmaH, int64_t indexUid, int32_t fid) {
- STsdb *pTsdb = pSmaH->pTsdb;
- ASSERT(!pSmaH->dFile.path && !pSmaH->dFile.pDB);
-
- pSmaH->dFile.fid = fid;
- char tSmaFile[TSDB_FILENAME_LEN] = {0};
- snprintf(tSmaFile, TSDB_FILENAME_LEN, "%" PRIi64 "%sv%df%d.tsma", indexUid, TD_DIRSEP, REPO_ID(pTsdb), fid);
- pSmaH->dFile.path = strdup(tSmaFile);
-
- return TSDB_CODE_SUCCESS;
-}
-
-/**
- * @brief
- *
- * @param pTsdb
- * @param interval Interval calculated by DB's precision
- * @param storageLevel
- * @return int32_t
- */
-static int32_t tsdbGetTSmaDays(STsdb *pTsdb, int64_t interval, int32_t storageLevel) {
- STsdbKeepCfg *pCfg = REPO_KEEP_CFG(pTsdb);
- int32_t daysPerFile = pCfg->days;
-
- if (storageLevel == SMA_STORAGE_LEVEL_TSDB) {
- int32_t days = SMA_STORAGE_TSDB_TIMES * (interval / tsTickPerMin[pCfg->precision]);
- daysPerFile = days > SMA_STORAGE_TSDB_DAYS ? days : SMA_STORAGE_TSDB_DAYS;
- }
-
- return daysPerFile;
-}
-
-static int tsdbSmaBeginCommit(SSmaEnv *pEnv) {
- TXN *pTxn = &pEnv->txn;
- // start a new txn
- tdbTxnOpen(pTxn, 0, poolMalloc, poolFree, pEnv->pPool, TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED);
- if (tdbBegin(pEnv->dbEnv, pTxn) != 0) {
- tsdbWarn("tsdbSma tdb begin commit fail");
- return -1;
- }
- return 0;
-}
-
-static int tsdbSmaEndCommit(SSmaEnv *pEnv) {
- TXN *pTxn = &pEnv->txn;
-
- // Commit current txn
- if (tdbCommit(pEnv->dbEnv, pTxn) != 0) {
- tsdbWarn("tsdbSma tdb end commit fail");
- return -1;
- }
- tdbTxnClose(pTxn);
- clearPool(pEnv->pPool);
- return 0;
-}
-
-/**
- * @brief Insert/Update Time-range-wise SMA data.
- * - If interval < SMA_STORAGE_SPLIT_HOURS(e.g. 24), save the SMA data as a part of DFileSet to e.g.
- * v3f1900.tsma.${sma_index_name}. The days is the same with that for TS data files.
- * - If interval >= SMA_STORAGE_SPLIT_HOURS, save the SMA data to e.g. vnode3/tsma/v3f632.tsma.${sma_index_name}. The
- * days is 30 times of the interval, and the minimum days is SMA_STORAGE_TSDB_DAYS(30d).
- * - The destination file of one data block for some interval is determined by its start TS key.
- *
- * @param pTsdb
- * @param msg
- * @return int32_t
- */
-static int32_t tsdbInsertTSmaDataImpl(STsdb *pTsdb, int64_t indexUid, const char *msg) {
- STsdbCfg *pCfg = REPO_CFG(pTsdb);
- const SArray *pDataBlocks = (const SArray *)msg;
-
- // TODO: destroy SSDataBlocks(msg)
-
- // For super table aggregation, the sma data is stored in vgroup calculated from the hash value of stable name. Thus
- // the sma data would arrive ahead of the update-expired-window msg.
- if (tsdbCheckAndInitSmaEnv(pTsdb, TSDB_SMA_TYPE_TIME_RANGE) != TSDB_CODE_SUCCESS) {
- terrno = TSDB_CODE_TDB_INIT_FAILED;
- return TSDB_CODE_FAILED;
- }
-
- if (!pDataBlocks) {
- terrno = TSDB_CODE_INVALID_PTR;
- tsdbWarn("vgId:%d insert tSma data failed since pDataBlocks is NULL", REPO_ID(pTsdb));
- return terrno;
- }
-
- if (taosArrayGetSize(pDataBlocks) <= 0) {
- terrno = TSDB_CODE_INVALID_PARA;
- tsdbWarn("vgId:%d insert tSma data failed since pDataBlocks is empty", REPO_ID(pTsdb));
- return TSDB_CODE_FAILED;
- }
-
- SSmaEnv *pEnv = REPO_TSMA_ENV(pTsdb);
- SSmaStat *pStat = SMA_ENV_STAT(pEnv);
- SSmaStatItem *pItem = NULL;
-
- tsdbRefSmaStat(pTsdb, pStat);
-
- if (pStat && SMA_STAT_ITEMS(pStat)) {
- pItem = taosHashGet(SMA_STAT_ITEMS(pStat), &indexUid, sizeof(indexUid));
- }
-
- if (!pItem || !(pItem = *(SSmaStatItem **)pItem) || tsdbSmaStatIsDropped(pItem)) {
- terrno = TSDB_CODE_TDB_INVALID_SMA_STAT;
- tsdbUnRefSmaStat(pTsdb, pStat);
- return TSDB_CODE_FAILED;
- }
-
- STSma *pSma = pItem->pSma;
- STSmaWriteH tSmaH = {0};
-
- if (tsdbInitTSmaWriteH(&tSmaH, pTsdb, pDataBlocks, pSma->interval, pSma->intervalUnit) != 0) {
- return TSDB_CODE_FAILED;
- }
-
- char rPath[TSDB_FILENAME_LEN] = {0};
- char aPath[TSDB_FILENAME_LEN] = {0};
- snprintf(rPath, TSDB_FILENAME_LEN, "%s%s%" PRIi64, SMA_ENV_PATH(pEnv), TD_DIRSEP, indexUid);
- tfsAbsoluteName(REPO_TFS(pTsdb), SMA_ENV_DID(pEnv), rPath, aPath);
- if (!taosCheckExistFile(aPath)) {
- if (tfsMkdirRecurAt(REPO_TFS(pTsdb), rPath, SMA_ENV_DID(pEnv)) != TSDB_CODE_SUCCESS) {
- tsdbUnRefSmaStat(pTsdb, pStat);
- return TSDB_CODE_FAILED;
- }
- }
-
- // Step 1: Judge the storage level and days
- int32_t storageLevel = tsdbGetSmaStorageLevel(pSma->interval, pSma->intervalUnit);
- int32_t daysPerFile = tsdbGetTSmaDays(pTsdb, tSmaH.interval, storageLevel);
-
- char smaKey[SMA_KEY_LEN] = {0}; // key: skey + groupId
- char dataBuf[512] = {0}; // val: aggr data // TODO: handle 512 buffer?
- void *pDataBuf = NULL;
- int32_t sz = taosArrayGetSize(pDataBlocks);
- for (int32_t i = 0; i < sz; ++i) {
- SSDataBlock *pDataBlock = taosArrayGet(pDataBlocks, i);
- int32_t colNum = pDataBlock->info.numOfCols;
- int32_t rows = pDataBlock->info.rows;
- int32_t rowSize = pDataBlock->info.rowSize;
- int64_t groupId = pDataBlock->info.groupId;
- for (int32_t j = 0; j < rows; ++j) {
- printf("|");
- TSKEY skey = TSKEY_INITIAL_VAL; // the start key of TS window by interval
- void *pSmaKey = &smaKey;
- bool isStartKey = false;
-
- int32_t tlen = 0; // reset the len
- pDataBuf = &dataBuf; // reset the buf
- for (int32_t k = 0; k < colNum; ++k) {
- SColumnInfoData *pColInfoData = taosArrayGet(pDataBlock->pDataBlock, k);
- void *var = POINTER_SHIFT(pColInfoData->pData, j * pColInfoData->info.bytes);
- switch (pColInfoData->info.type) {
- case TSDB_DATA_TYPE_TIMESTAMP:
- if (!isStartKey) {
- isStartKey = true;
- skey = *(TSKEY *)var;
- printf("= skey %" PRIi64 " groupId = %" PRIi64 "|", skey, groupId);
- tsdbEncodeTSmaKey(groupId, skey, &pSmaKey);
- } else {
- printf(" %" PRIi64 " |", *(int64_t *)var);
- tlen += taosEncodeFixedI64(&pDataBuf, *(int64_t *)var);
- break;
- }
- break;
- case TSDB_DATA_TYPE_BOOL:
- case TSDB_DATA_TYPE_UTINYINT:
- printf(" %15d |", *(uint8_t *)var);
- tlen += taosEncodeFixedU8(&pDataBuf, *(uint8_t *)var);
- break;
- case TSDB_DATA_TYPE_TINYINT:
- printf(" %15d |", *(int8_t *)var);
- tlen += taosEncodeFixedI8(&pDataBuf, *(int8_t *)var);
- break;
- case TSDB_DATA_TYPE_SMALLINT:
- printf(" %15d |", *(int16_t *)var);
- tlen += taosEncodeFixedI16(&pDataBuf, *(int16_t *)var);
- break;
- case TSDB_DATA_TYPE_USMALLINT:
- printf(" %15d |", *(uint16_t *)var);
- tlen += taosEncodeFixedU16(&pDataBuf, *(uint16_t *)var);
- break;
- case TSDB_DATA_TYPE_INT:
- printf(" %15d |", *(int32_t *)var);
- tlen += taosEncodeFixedI32(&pDataBuf, *(int32_t *)var);
- break;
- case TSDB_DATA_TYPE_FLOAT:
- printf(" %15f |", *(float *)var);
- tlen += taosEncodeBinary(&pDataBuf, var, sizeof(float));
- break;
- case TSDB_DATA_TYPE_UINT:
- printf(" %15u |", *(uint32_t *)var);
- tlen += taosEncodeFixedU32(&pDataBuf, *(uint32_t *)var);
- break;
- case TSDB_DATA_TYPE_BIGINT:
- printf(" %15ld |", *(int64_t *)var);
- tlen += taosEncodeFixedI64(&pDataBuf, *(int64_t *)var);
- break;
- case TSDB_DATA_TYPE_DOUBLE:
- printf(" %15lf |", *(double *)var);
- tlen += taosEncodeBinary(&pDataBuf, var, sizeof(double));
- case TSDB_DATA_TYPE_UBIGINT:
- printf(" %15lu |", *(uint64_t *)var);
- tlen += taosEncodeFixedU64(&pDataBuf, *(uint64_t *)var);
- break;
- case TSDB_DATA_TYPE_NCHAR: {
- char tmpChar[100] = {0};
- strncpy(tmpChar, varDataVal(var), varDataLen(var));
- printf(" %s |", tmpChar);
- tlen += taosEncodeBinary(&pDataBuf, varDataVal(var), varDataLen(var));
- break;
- }
- case TSDB_DATA_TYPE_VARCHAR: { // TSDB_DATA_TYPE_BINARY
- char tmpChar[100] = {0};
- strncpy(tmpChar, varDataVal(var), varDataLen(var));
- printf(" %s |", tmpChar);
- tlen += taosEncodeBinary(&pDataBuf, varDataVal(var), varDataLen(var));
- break;
- }
- case TSDB_DATA_TYPE_VARBINARY:
- // TODO: add binary/varbinary
- TASSERT(0);
- default:
- printf("the column type %" PRIi16 " is undefined\n", pColInfoData->info.type);
- TASSERT(0);
- break;
- }
- }
- // if ((tlen > 0) && (skey != TSKEY_INITIAL_VAL)) {
- if (tlen > 0) {
- int32_t fid = (int32_t)(TSDB_KEY_FID(skey, daysPerFile, pCfg->precision));
-
- // Step 2: Set the DFile for storage of SMA index, and iterate/split the TSma data and store to B+Tree index
- // file
- // - Set and open the DFile or the B+Tree file
- // TODO: tsdbStartTSmaCommit();
- if (fid != tSmaH.dFile.fid) {
- if (tSmaH.dFile.fid != TSDB_IVLD_FID) {
- tsdbSmaEndCommit(pEnv);
- tsdbCloseDBF(&tSmaH.dFile);
- }
- tsdbSetTSmaDataFile(&tSmaH, indexUid, fid);
- if (tsdbOpenDBF(pEnv->dbEnv, &tSmaH.dFile) != 0) {
- tsdbWarn("vgId:%d open DB file %s failed since %s", REPO_ID(pTsdb),
- tSmaH.dFile.path ? tSmaH.dFile.path : "path is NULL", tstrerror(terrno));
- tsdbDestroyTSmaWriteH(&tSmaH);
- tsdbUnRefSmaStat(pTsdb, pStat);
- return TSDB_CODE_FAILED;
- }
- tsdbSmaBeginCommit(pEnv);
- }
-
- if (tsdbInsertTSmaBlocks(&tSmaH, &smaKey, SMA_KEY_LEN, dataBuf, tlen, &pEnv->txn) != 0) {
- tsdbWarn("vgId:%d insert tsma data blocks fail for index %" PRIi64 ", skey %" PRIi64 ", groupId %" PRIi64
- " since %s",
- REPO_ID(pTsdb), indexUid, skey, groupId, tstrerror(terrno));
- tsdbSmaEndCommit(pEnv);
- tsdbDestroyTSmaWriteH(&tSmaH);
- tsdbUnRefSmaStat(pTsdb, pStat);
- return TSDB_CODE_FAILED;
- }
- tsdbDebug("vgId:%d insert tsma data blocks success for index %" PRIi64 ", skey %" PRIi64 ", groupId %" PRIi64,
- REPO_ID(pTsdb), indexUid, skey, groupId);
- // TODO:tsdbEndTSmaCommit();
-
- // Step 3: reset the SSmaStat
- tsdbResetExpiredWindow(pTsdb, pStat, indexUid, skey);
- } else {
- tsdbWarn("vgId:%d invalid data skey:%" PRIi64 ", tlen %" PRIi32 " during insert tSma data for %" PRIi64,
- REPO_ID(pTsdb), skey, tlen, indexUid);
- }
-
- printf("\n");
- }
- }
- tsdbSmaEndCommit(pEnv); // TODO: not commit for every insert
- tsdbDestroyTSmaWriteH(&tSmaH);
- tsdbUnRefSmaStat(pTsdb, pStat);
-
- return TSDB_CODE_SUCCESS;
-}
-
-/**
- * @brief Drop tSma data and local cache
- * - insert/query reference
- * @param pTsdb
- * @param msg
- * @return int32_t
- */
-static int32_t tsdbDropTSmaDataImpl(STsdb *pTsdb, int64_t indexUid) {
- SSmaEnv *pEnv = atomic_load_ptr(&REPO_TSMA_ENV(pTsdb));
-
- // clear local cache
- if (pEnv) {
- tsdbDebug("vgId:%d drop tSma local cache for %" PRIi64, REPO_ID(pTsdb), indexUid);
-
- SSmaStatItem *pItem = taosHashGet(SMA_ENV_STAT_ITEMS(pEnv), &indexUid, sizeof(indexUid));
- if ((pItem) || ((pItem = *(SSmaStatItem **)pItem))) {
- if (tsdbSmaStatIsDropped(pItem)) {
- tsdbDebug("vgId:%d tSma stat is already dropped for %" PRIi64, REPO_ID(pTsdb), indexUid);
- return TSDB_CODE_TDB_INVALID_ACTION; // TODO: duplicate drop msg would be intercepted by mnode
- }
-
- tsdbWLockSma(pEnv);
- if (tsdbSmaStatIsDropped(pItem)) {
- tsdbUnLockSma(pEnv);
- tsdbDebug("vgId:%d tSma stat is already dropped for %" PRIi64, REPO_ID(pTsdb), indexUid);
- return TSDB_CODE_TDB_INVALID_ACTION; // TODO: duplicate drop msg would be intercepted by mnode
- }
- tsdbSmaStatSetDropped(pItem);
- tsdbUnLockSma(pEnv);
-
- int32_t nSleep = 0;
- int32_t refVal = INT32_MAX;
- while (true) {
- if ((refVal = T_REF_VAL_GET(SMA_ENV_STAT(pEnv))) <= 0) {
- tsdbDebug("vgId:%d drop index %" PRIi64 " since refVal=%d", REPO_ID(pTsdb), indexUid, refVal);
- break;
- }
- tsdbDebug("vgId:%d wait 1s to drop index %" PRIi64 " since refVal=%d", REPO_ID(pTsdb), indexUid, refVal);
- taosSsleep(1);
- if (++nSleep > SMA_DROP_EXPIRED_TIME) {
- tsdbDebug("vgId:%d drop index %" PRIi64 " after wait %d (refVal=%d)", REPO_ID(pTsdb), indexUid, nSleep,
- refVal);
- break;
- };
- }
-
- tsdbFreeSmaStatItem(pItem);
- tsdbDebug("vgId:%d getTSmaDataImpl failed since no index %" PRIi64 " in local cache", REPO_ID(pTsdb), indexUid);
- }
- }
- // clear sma data files
- // TODO:
- return TSDB_CODE_SUCCESS;
-}
-
-static int32_t tsdbSetRSmaDataFile(STSmaWriteH *pSmaH, int32_t fid) {
- STsdb *pTsdb = pSmaH->pTsdb;
-
- char tSmaFile[TSDB_FILENAME_LEN] = {0};
- snprintf(tSmaFile, TSDB_FILENAME_LEN, "v%df%d.rsma", REPO_ID(pTsdb), fid);
- pSmaH->dFile.path = strdup(tSmaFile);
-
- return TSDB_CODE_SUCCESS;
-}
-
-static int32_t tsdbInsertRSmaDataImpl(STsdb *pTsdb, const char *msg) {
- STsdbCfg *pCfg = REPO_CFG(pTsdb);
- const SArray *pDataBlocks = (const SArray *)msg;
- SSmaEnv *pEnv = atomic_load_ptr(&REPO_RSMA_ENV(pTsdb));
- int64_t indexUid = SMA_TEST_INDEX_UID;
-
- if (!pEnv) {
- terrno = TSDB_CODE_INVALID_PTR;
- tsdbWarn("vgId:%d insert rSma data failed since pTSmaEnv is NULL", REPO_ID(pTsdb));
- return terrno;
- }
-
- if (!pDataBlocks) {
- terrno = TSDB_CODE_INVALID_PTR;
- tsdbWarn("vgId:%d insert rSma data failed since pDataBlocks is NULL", REPO_ID(pTsdb));
- return terrno;
- }
-
- if (taosArrayGetSize(pDataBlocks) <= 0) {
- terrno = TSDB_CODE_INVALID_PARA;
- tsdbWarn("vgId:%d insert rSma data failed since pDataBlocks is empty", REPO_ID(pTsdb));
- return TSDB_CODE_FAILED;
- }
-
- SSmaStat *pStat = SMA_ENV_STAT(pEnv);
- SSmaStatItem *pItem = NULL;
-
- tsdbRefSmaStat(pTsdb, pStat);
-
- if (pStat && SMA_STAT_ITEMS(pStat)) {
- pItem = taosHashGet(SMA_STAT_ITEMS(pStat), &indexUid, sizeof(indexUid));
- }
-
- if (!pItem || !(pItem = *(SSmaStatItem **)pItem) || tsdbSmaStatIsDropped(pItem)) {
- terrno = TSDB_CODE_TDB_INVALID_SMA_STAT;
- tsdbUnRefSmaStat(pTsdb, pStat);
- return TSDB_CODE_FAILED;
- }
-
- STSma *pSma = pItem->pSma;
-
- STSmaWriteH tSmaH = {0};
-
- if (tsdbInitTSmaWriteH(&tSmaH, pTsdb, pDataBlocks, pSma->interval, pSma->intervalUnit) != 0) {
- return TSDB_CODE_FAILED;
- }
-
- char rPath[TSDB_FILENAME_LEN] = {0};
- char aPath[TSDB_FILENAME_LEN] = {0};
- snprintf(rPath, TSDB_FILENAME_LEN, "%s%s%" PRIi64, SMA_ENV_PATH(pEnv), TD_DIRSEP, indexUid);
- tfsAbsoluteName(REPO_TFS(pTsdb), SMA_ENV_DID(pEnv), rPath, aPath);
- if (!taosCheckExistFile(aPath)) {
- if (tfsMkdirRecurAt(REPO_TFS(pTsdb), rPath, SMA_ENV_DID(pEnv)) != TSDB_CODE_SUCCESS) {
- return TSDB_CODE_FAILED;
- }
- }
-
- // Step 1: Judge the storage level and days
- int32_t storageLevel = tsdbGetSmaStorageLevel(pSma->interval, pSma->intervalUnit);
- int32_t daysPerFile = tsdbGetTSmaDays(pTsdb, tSmaH.interval, storageLevel);
-#if 0
- int32_t fid = (int32_t)(TSDB_KEY_FID(pData->skey, daysPerFile, pCfg->precision));
-
- // Step 2: Set the DFile for storage of SMA index, and iterate/split the TSma data and store to B+Tree index file
- // - Set and open the DFile or the B+Tree file
- // TODO: tsdbStartTSmaCommit();
- tsdbSetTSmaDataFile(&tSmaH, pData, indexUid, fid);
- if (tsdbOpenDBF(pTsdb->pTSmaEnv->dbEnv, &tSmaH.dFile) != 0) {
- tsdbWarn("vgId:%d open DB file %s failed since %s", REPO_ID(pTsdb),
- tSmaH.dFile.path ? tSmaH.dFile.path : "path is NULL", tstrerror(terrno));
- tsdbDestroyTSmaWriteH(&tSmaH);
- return TSDB_CODE_FAILED;
- }
-
- if (tsdbInsertTSmaDataSection(&tSmaH, pData) != 0) {
- tsdbWarn("vgId:%d insert tSma data section failed since %s", REPO_ID(pTsdb), tstrerror(terrno));
- tsdbDestroyTSmaWriteH(&tSmaH);
- return TSDB_CODE_FAILED;
- }
- // TODO:tsdbEndTSmaCommit();
-
- // Step 3: reset the SSmaStat
- tsdbResetExpiredWindow(pTsdb, SMA_ENV_STAT(pTsdb->pTSmaEnv), pData->indexUid, pData->skey);
-#endif
-
- tsdbDestroyTSmaWriteH(&tSmaH);
- tsdbUnRefSmaStat(pTsdb, pStat);
- return TSDB_CODE_SUCCESS;
-}
-
-/**
- * @brief
- *
- * @param pSmaH
- * @param pTsdb
- * @param interval
- * @param intervalUnit
- * @return int32_t
- */
-static int32_t tsdbInitTSmaReadH(STSmaReadH *pSmaH, STsdb *pTsdb, int64_t interval, int8_t intervalUnit) {
- pSmaH->pTsdb = pTsdb;
- pSmaH->interval = tsdbGetIntervalByPrecision(interval, intervalUnit, REPO_CFG(pTsdb)->precision, true);
- pSmaH->storageLevel = tsdbGetSmaStorageLevel(interval, intervalUnit);
- pSmaH->days = tsdbGetTSmaDays(pTsdb, pSmaH->interval, pSmaH->storageLevel);
- return TSDB_CODE_SUCCESS;
-}
-
-/**
- * @brief Init of tSma FS
- *
- * @param pReadH
- * @param indexUid
- * @param skey
- * @return int32_t
- */
-static int32_t tsdbInitTSmaFile(STSmaReadH *pSmaH, int64_t indexUid, TSKEY skey) {
- STsdb *pTsdb = pSmaH->pTsdb;
-
- int32_t fid = (int32_t)(TSDB_KEY_FID(skey, pSmaH->days, REPO_CFG(pTsdb)->precision));
- char tSmaFile[TSDB_FILENAME_LEN] = {0};
- snprintf(tSmaFile, TSDB_FILENAME_LEN, "%" PRIi64 "%sv%df%d.tsma", indexUid, TD_DIRSEP, REPO_ID(pTsdb), fid);
- pSmaH->dFile.path = strdup(tSmaFile);
- pSmaH->smaFsIter.iter = 0;
- pSmaH->smaFsIter.fid = fid;
- return TSDB_CODE_SUCCESS;
-}
-
-/**
- * @brief Set and open tSma file if it has key locates in queryWin.
- *
- * @param pReadH
- * @param param
- * @param queryWin
- * @return true
- * @return false
- */
-static bool tsdbSetAndOpenTSmaFile(STSmaReadH *pReadH, TSKEY *queryKey) {
- SArray *smaFs = pReadH->pTsdb->fs->cstatus->sf;
- int32_t nSmaFs = taosArrayGetSize(smaFs);
-
- tsdbCloseDBF(&pReadH->dFile);
-
-#if 0
- while (pReadH->smaFsIter.iter < nSmaFs) {
- void *pSmaFile = taosArrayGet(smaFs, pReadH->smaFsIter.iter);
- if (pSmaFile) { // match(indexName, queryWindow)
- // TODO: select the file by index_name ...
- pReadH->dFile = pSmaFile;
- ++pReadH->smaFsIter.iter;
- break;
- }
- ++pReadH->smaFsIter.iter;
- }
-
- if (pReadH->pDFile) {
- tsdbDebug("vg%d: smaFile %s matched", REPO_ID(pReadH->pTsdb), "[pSmaFile dir]");
- return true;
- }
-#endif
-
- return false;
-}
-
-/**
- * @brief
- *
- * @param pTsdb Return the data between queryWin and fill the pData.
- * @param pData
- * @param indexUid
- * @param pQuerySKey
- * @param nMaxResult The query invoker should control the nMaxResult need to return to avoid OOM.
- * @return int32_t
- */
-static int32_t tsdbGetTSmaDataImpl(STsdb *pTsdb, char *pData, int64_t indexUid, TSKEY querySKey, int32_t nMaxResult) {
- SSmaEnv *pEnv = atomic_load_ptr(&REPO_TSMA_ENV(pTsdb));
- SSmaStat *pStat = NULL;
-
- if (!pEnv) {
- terrno = TSDB_CODE_INVALID_PTR;
- tsdbWarn("vgId:%d getTSmaDataImpl failed since pTSmaEnv is NULL", REPO_ID(pTsdb));
- return TSDB_CODE_FAILED;
- }
-
- pStat = SMA_ENV_STAT(pEnv);
-
- tsdbRefSmaStat(pTsdb, pStat);
- SSmaStatItem *pItem = taosHashGet(SMA_ENV_STAT_ITEMS(pEnv), &indexUid, sizeof(indexUid));
- if (!pItem || !(pItem = *(SSmaStatItem **)pItem)) {
- // Normally pItem should not be NULL, mark all windows as expired and notify query module to fetch raw TS data if
- // it's NULL.
- tsdbUnRefSmaStat(pTsdb, pStat);
- terrno = TSDB_CODE_TDB_INVALID_ACTION;
- tsdbDebug("vgId:%d getTSmaDataImpl failed since no index %" PRIi64, REPO_ID(pTsdb), indexUid);
- return TSDB_CODE_FAILED;
- }
-
-#if 0
- int32_t nQueryWin = taosArrayGetSize(pQuerySKey);
- for (int32_t n = 0; n < nQueryWin; ++n) {
- TSKEY skey = taosArrayGet(pQuerySKey, n);
- if (taosHashGet(pItem->expiredWindows, &skey, sizeof(TSKEY))) {
- // TODO: mark this window as expired.
- }
- }
-#endif
-
-#if 1
- int8_t smaStat = 0;
- if (!tsdbSmaStatIsOK(pItem, &smaStat)) { // TODO: multiple check for large scale sma query
- tsdbUnRefSmaStat(pTsdb, pStat);
- terrno = TSDB_CODE_TDB_INVALID_SMA_STAT;
- tsdbWarn("vgId:%d getTSmaDataImpl failed from index %" PRIi64 " since %s %" PRIi8, REPO_ID(pTsdb), indexUid,
- tstrerror(terrno), smaStat);
- return TSDB_CODE_FAILED;
- }
-
- if (taosHashGet(pItem->expiredWindows, &querySKey, sizeof(TSKEY))) {
- // TODO: mark this window as expired.
- tsdbDebug("vgId:%d skey %" PRIi64 " of window exists in expired window for index %" PRIi64, REPO_ID(pTsdb),
- querySKey, indexUid);
- } else {
- tsdbDebug("vgId:%d skey %" PRIi64 " of window not in expired window for index %" PRIi64, REPO_ID(pTsdb), querySKey,
- indexUid);
- }
-
- STSma *pTSma = pItem->pSma;
-#endif
-
- STSmaReadH tReadH = {0};
- tsdbInitTSmaReadH(&tReadH, pTsdb, pTSma->interval, pTSma->intervalUnit);
- tsdbCloseDBF(&tReadH.dFile);
-
- tsdbUnRefSmaStat(pTsdb, pStat);
-
- tsdbInitTSmaFile(&tReadH, indexUid, querySKey);
- if (tsdbOpenDBF(pEnv->dbEnv, &tReadH.dFile) != 0) {
- tsdbWarn("vgId:%d open DBF %s failed since %s", REPO_ID(pTsdb), tReadH.dFile.path, tstrerror(terrno));
- return TSDB_CODE_FAILED;
- }
-
- char smaKey[SMA_KEY_LEN] = {0};
- void *pSmaKey = &smaKey;
- int64_t queryGroupId = 1;
- tsdbEncodeTSmaKey(queryGroupId, querySKey, (void **)&pSmaKey);
-
- tsdbDebug("vgId:%d get sma data from %s: smaKey %" PRIx64 "-%" PRIx64 ", keyLen %d", REPO_ID(pTsdb),
- tReadH.dFile.path, *(int64_t *)smaKey, *(int64_t *)POINTER_SHIFT(smaKey, 8), SMA_KEY_LEN);
-
- void *result = NULL;
- int32_t valueSize = 0;
- if (!(result = tsdbGetSmaDataByKey(&tReadH.dFile, smaKey, SMA_KEY_LEN, &valueSize))) {
- tsdbWarn("vgId:%d get sma data failed from smaIndex %" PRIi64 ", smaKey %" PRIx64 "-%" PRIx64 " since %s",
- REPO_ID(pTsdb), indexUid, *(int64_t *)smaKey, *(int64_t *)POINTER_SHIFT(smaKey, 8), tstrerror(terrno));
- tsdbCloseDBF(&tReadH.dFile);
- return TSDB_CODE_FAILED;
- }
-
-#ifdef _TEST_SMA_PRINT_DEBUG_LOG_
- for (uint32_t v = 0; v < valueSize; v += 8) {
- tsdbWarn("vgId:%d get sma data v[%d]=%" PRIi64, REPO_ID(pTsdb), v, *(int64_t *)POINTER_SHIFT(result, v));
- }
-#endif
- taosMemoryFreeClear(result); // TODO: fill the result to output
-
-#if 0
- int32_t nResult = 0;
- int64_t lastKey = 0;
-
- while (true) {
- if (nResult >= nMaxResult) {
- break;
- }
-
- // set and open the file according to the STSma param
- if (tsdbSetAndOpenTSmaFile(&tReadH, queryWin)) {
- char bTree[100] = "\0";
- while (strncmp(bTree, "has more nodes", 100) == 0) {
- if (nResult >= nMaxResult) {
- break;
- }
- // tsdbGetDataFromBTree(bTree, queryWin, lastKey)
- // fill the pData
- ++nResult;
- }
- }
- }
-#endif
- // read data from file and fill the result
- tsdbCloseDBF(&tReadH.dFile);
- return TSDB_CODE_SUCCESS;
-}
-
-int32_t tsdbCreateTSma(STsdb *pTsdb, char *pMsg) {
- SSmaCfg vCreateSmaReq = {0};
- if (!tDeserializeSVCreateTSmaReq(pMsg, &vCreateSmaReq)) {
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- tsdbWarn("vgId:%d tsma create msg received but deserialize failed since %s", REPO_ID(pTsdb), terrstr(terrno));
- return -1;
- }
-
- tsdbDebug("vgId:%d tsma create msg %s:%" PRIi64 " for table %" PRIi64 " received", REPO_ID(pTsdb),
- vCreateSmaReq.tSma.indexName, vCreateSmaReq.tSma.indexUid, vCreateSmaReq.tSma.tableUid);
-
- // record current timezone of server side
- vCreateSmaReq.tSma.timezoneInt = tsTimezone;
-
- if (metaCreateTSma(REPO_META(pTsdb), &vCreateSmaReq) < 0) {
- // TODO: handle error
- tsdbWarn("vgId:%d tsma %s:%" PRIi64 " create failed for table %" PRIi64 " since %s", REPO_ID(pTsdb),
- vCreateSmaReq.tSma.indexName, vCreateSmaReq.tSma.indexUid, vCreateSmaReq.tSma.tableUid, terrstr(terrno));
- tdDestroyTSma(&vCreateSmaReq.tSma);
- return -1;
- }
-
- tsdbTSmaAdd(pTsdb, 1);
-
- tdDestroyTSma(&vCreateSmaReq.tSma);
- // TODO: return directly or go on follow steps?
- return TSDB_CODE_SUCCESS;
-}
-
-int32_t tsdbDropTSma(STsdb *pTsdb, char *pMsg) {
- SVDropTSmaReq vDropSmaReq = {0};
- if (!tDeserializeSVDropTSmaReq(pMsg, &vDropSmaReq)) {
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- return -1;
- }
-
- // TODO: send msg to stream computing to drop tSma
- // if ((send msg to stream computing) < 0) {
- // tdDestroyTSma(&vCreateSmaReq);
- // return -1;
- // }
- //
-
- if (metaDropTSma(REPO_META(pTsdb), vDropSmaReq.indexUid) < 0) {
- // TODO: handle error
- return -1;
- }
-
- if (tsdbDropTSmaData(pTsdb, vDropSmaReq.indexUid) < 0) {
- // TODO: handle error
- return -1;
- }
-
- tsdbTSmaSub(pTsdb, 1);
-
- // TODO: return directly or go on follow steps?
- return TSDB_CODE_SUCCESS;
-}
-
-/**
- * @brief Check and init qTaskInfo_t, only applicable to stable with SRSmaParam.
- *
- * @param pTsdb
- * @param pMeta
- * @param pReq
- * @return int32_t
- */
-int32_t tsdbRegisterRSma(STsdb *pTsdb, SMeta *pMeta, SVCreateStbReq *pReq, SMsgCb *pMsgCb) {
- if (!pReq->rollup) {
- tsdbDebug("vgId:%d return directly since no rollup for stable %s %" PRIi64, REPO_ID(pTsdb), pReq->name, pReq->suid);
- return TSDB_CODE_SUCCESS;
- }
-
- SRSmaParam *param = &pReq->pRSmaParam;
-
- if ((param->qmsg1Len == 0) && (param->qmsg2Len == 0)) {
- tsdbWarn("vgId:%d no qmsg1/qmsg2 for rollup stable %s %" PRIi64, REPO_ID(pTsdb), pReq->name, pReq->suid);
- return TSDB_CODE_SUCCESS;
- }
-
- if (tsdbCheckAndInitSmaEnv(pTsdb, TSDB_SMA_TYPE_ROLLUP) != TSDB_CODE_SUCCESS) {
- terrno = TSDB_CODE_TDB_INIT_FAILED;
- return TSDB_CODE_FAILED;
- }
-
- SSmaEnv *pEnv = REPO_RSMA_ENV(pTsdb);
- SSmaStat *pStat = SMA_ENV_STAT(pEnv);
- SRSmaInfo *pRSmaInfo = NULL;
-
- pRSmaInfo = taosHashGet(SMA_STAT_INFO_HASH(pStat), &pReq->suid, sizeof(tb_uid_t));
- if (pRSmaInfo) {
- tsdbWarn("vgId:%d rsma info already exists for stb: %s, %" PRIi64, REPO_ID(pTsdb), pReq->name, pReq->suid);
- return TSDB_CODE_SUCCESS;
- }
-
- pRSmaInfo = (SRSmaInfo *)taosMemoryCalloc(1, sizeof(SRSmaInfo));
- if (!pRSmaInfo) {
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- return TSDB_CODE_FAILED;
- }
-
- STqReadHandle *pReadHandle = tqInitSubmitMsgScanner(pMeta);
- if (!pReadHandle) {
- taosMemoryFree(pRSmaInfo);
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- return TSDB_CODE_FAILED;
- }
-
- SReadHandle handle = {
- .reader = pReadHandle,
- .meta = pMeta,
- .pMsgCb = pMsgCb,
- };
-
- if (param->qmsg1) {
- pRSmaInfo->taskInfo[0] = qCreateStreamExecTaskInfo(param->qmsg1, &handle);
- if (!pRSmaInfo->taskInfo[0]) {
- taosMemoryFree(pRSmaInfo);
- taosMemoryFree(pReadHandle);
- return TSDB_CODE_FAILED;
- }
- }
-
- if (param->qmsg2) {
- pRSmaInfo->taskInfo[1] = qCreateStreamExecTaskInfo(param->qmsg2, &handle);
- if (!pRSmaInfo->taskInfo[1]) {
- taosMemoryFree(pRSmaInfo);
- taosMemoryFree(pReadHandle);
- return TSDB_CODE_FAILED;
- }
- }
-
- if (taosHashPut(SMA_STAT_INFO_HASH(pStat), &pReq->suid, sizeof(tb_uid_t), &pRSmaInfo, sizeof(pRSmaInfo)) !=
- TSDB_CODE_SUCCESS) {
- return TSDB_CODE_FAILED;
- } else {
- tsdbDebug("vgId:%d register rsma info succeed for suid:%" PRIi64, REPO_ID(pTsdb), pReq->suid);
- }
-
- return TSDB_CODE_SUCCESS;
-}
-
-/**
- * @brief store suid/[uids], prefer to use array and then hash
- *
- * @param pStore
- * @param suid
- * @param uid
- * @return int32_t
- */
-static int32_t tsdbUidStorePut(STbUidStore *pStore, tb_uid_t suid, tb_uid_t *uid) {
- // prefer to store suid/uids in array
- if ((suid == pStore->suid) || (pStore->suid == 0)) {
- if (pStore->suid == 0) {
- pStore->suid = suid;
- }
- if (uid) {
- if (!pStore->tbUids) {
- if (!(pStore->tbUids = taosArrayInit(1, sizeof(tb_uid_t)))) {
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- return TSDB_CODE_FAILED;
- }
- }
- if (!taosArrayPush(pStore->tbUids, uid)) {
- return TSDB_CODE_FAILED;
- }
- }
- } else {
- // store other suid/uids in hash when multiple stable/table included in 1 batch of request
- if (!pStore->uidHash) {
- pStore->uidHash = taosHashInit(4, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), false, HASH_ENTRY_LOCK);
- if (!pStore->uidHash) {
- return TSDB_CODE_FAILED;
- }
- }
- if (uid) {
- SArray *uidArray = taosHashGet(pStore->uidHash, &suid, sizeof(tb_uid_t));
- if (uidArray && ((uidArray = *(SArray **)uidArray))) {
- taosArrayPush(uidArray, uid);
- } else {
- SArray *pUidArray = taosArrayInit(1, sizeof(tb_uid_t));
- if (!pUidArray) {
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- return TSDB_CODE_FAILED;
- }
- if (!taosArrayPush(pUidArray, uid)) {
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- return TSDB_CODE_FAILED;
- }
- if (taosHashPut(pStore->uidHash, &suid, sizeof(suid), &pUidArray, sizeof(pUidArray)) != 0) {
- return TSDB_CODE_FAILED;
- }
- }
- } else {
- if (taosHashPut(pStore->uidHash, &suid, sizeof(suid), NULL, 0) != 0) {
- return TSDB_CODE_FAILED;
- }
- }
- }
- return TSDB_CODE_SUCCESS;
-}
-
-void tsdbUidStoreDestory(STbUidStore *pStore) {
- if (pStore) {
- if (pStore->uidHash) {
- if (pStore->tbUids) {
- // When pStore->tbUids not NULL, the pStore->uidHash has k/v; otherwise pStore->uidHash only has keys.
- void *pIter = taosHashIterate(pStore->uidHash, NULL);
- while (pIter) {
- SArray *arr = *(SArray **)pIter;
- taosArrayDestroy(arr);
- pIter = taosHashIterate(pStore->uidHash, pIter);
- }
- }
- taosHashCleanup(pStore->uidHash);
- }
- taosArrayDestroy(pStore->tbUids);
- }
-}
-
-void *tsdbUidStoreFree(STbUidStore *pStore) {
- if (pStore) {
- tsdbUidStoreDestory(pStore);
- taosMemoryFree(pStore);
- }
- return NULL;
-}
-
-/**
- * @brief fetch suid/uids when create child tables of rollup SMA
- *
- * @param pTsdb
- * @param ppStore
- * @param suid
- * @param uid
- * @return int32_t
- */
-int32_t tsdbFetchTbUidList(STsdb *pTsdb, STbUidStore **ppStore, tb_uid_t suid, tb_uid_t uid) {
- SSmaEnv *pEnv = REPO_RSMA_ENV((STsdb *)pTsdb);
-
- // only applicable to rollup SMA ctables
- if (!pEnv) {
- return TSDB_CODE_SUCCESS;
- }
-
- SSmaStat *pStat = SMA_ENV_STAT(pEnv);
- SHashObj *infoHash = NULL;
- if (!pStat || !(infoHash = SMA_STAT_INFO_HASH(pStat))) {
- terrno = TSDB_CODE_TDB_INVALID_SMA_STAT;
- return TSDB_CODE_FAILED;
- }
-
- // info cached when create rsma stable and return directly for non-rsma ctables
- if (!taosHashGet(infoHash, &suid, sizeof(tb_uid_t))) {
- return TSDB_CODE_SUCCESS;
- }
-
- ASSERT(ppStore != NULL);
-
- if (!(*ppStore)) {
- if (tsdbUidStoreInit(ppStore) != 0) {
- return TSDB_CODE_FAILED;
- }
- }
-
- if (tsdbUidStorePut(*ppStore, suid, &uid) != 0) {
- *ppStore = tsdbUidStoreFree(*ppStore);
- return TSDB_CODE_FAILED;
- }
-
- return TSDB_CODE_SUCCESS;
-}
-
-static FORCE_INLINE int32_t tsdbUpdateTbUidListImpl(STsdb *pTsdb, tb_uid_t *suid, SArray *tbUids) {
- SSmaEnv *pEnv = REPO_RSMA_ENV(pTsdb);
- SSmaStat *pStat = SMA_ENV_STAT(pEnv);
- SRSmaInfo *pRSmaInfo = NULL;
-
- if (!suid || !tbUids) {
- terrno = TSDB_CODE_INVALID_PTR;
- tsdbError("vgId:%d failed to get rsma info for uid:%" PRIi64 " since %s", REPO_ID(pTsdb), *suid, terrstr(terrno));
- return TSDB_CODE_FAILED;
- }
-
- pRSmaInfo = taosHashGet(SMA_STAT_INFO_HASH(pStat), suid, sizeof(tb_uid_t));
- if (!pRSmaInfo || !(pRSmaInfo = *(SRSmaInfo **)pRSmaInfo)) {
- tsdbError("vgId:%d failed to get rsma info for uid:%" PRIi64, REPO_ID(pTsdb), *suid);
- terrno = TSDB_CODE_TDB_INVALID_SMA_STAT;
- return TSDB_CODE_FAILED;
- }
-
- if (pRSmaInfo->taskInfo[0] && (qUpdateQualifiedTableId(pRSmaInfo->taskInfo[0], tbUids, true) != 0)) {
- tsdbError("vgId:%d update tbUidList failed for uid:%" PRIi64 " since %s", REPO_ID(pTsdb), *suid, terrstr(terrno));
- return TSDB_CODE_FAILED;
- } else {
- tsdbDebug("vgId:%d update tbUidList succeed for qTaskInfo:%p with suid:%" PRIi64 ", uid:%" PRIi64, REPO_ID(pTsdb),
- pRSmaInfo->taskInfo[0], *suid, *(int64_t *)taosArrayGet(tbUids, 0));
- }
-
- if (pRSmaInfo->taskInfo[1] && (qUpdateQualifiedTableId(pRSmaInfo->taskInfo[1], tbUids, true) != 0)) {
- tsdbError("vgId:%d update tbUidList failed for uid:%" PRIi64 " since %s", REPO_ID(pTsdb), *suid, terrstr(terrno));
- return TSDB_CODE_FAILED;
- } else {
- tsdbDebug("vgId:%d update tbUidList succeed for qTaskInfo:%p with suid:%" PRIi64 ", uid:%" PRIi64, REPO_ID(pTsdb),
- pRSmaInfo->taskInfo[1], *suid, *(int64_t *)taosArrayGet(tbUids, 0));
- }
-
- return TSDB_CODE_SUCCESS;
-}
-
-int32_t tsdbUpdateTbUidList(STsdb *pTsdb, STbUidStore *pStore) {
- if (!pStore || (taosArrayGetSize(pStore->tbUids) == 0)) {
- return TSDB_CODE_SUCCESS;
- }
-
- if (tsdbUpdateTbUidListImpl(pTsdb, &pStore->suid, pStore->tbUids) != TSDB_CODE_SUCCESS) {
- return TSDB_CODE_FAILED;
- }
-
- void *pIter = taosHashIterate(pStore->uidHash, NULL);
- while (pIter) {
- tb_uid_t *pTbSuid = (tb_uid_t *)taosHashGetKey(pIter, NULL);
- SArray *pTbUids = *(SArray **)pIter;
-
- if (tsdbUpdateTbUidListImpl(pTsdb, pTbSuid, pTbUids) != TSDB_CODE_SUCCESS) {
- taosHashCancelIterate(pStore->uidHash, pIter);
- return TSDB_CODE_FAILED;
- }
-
- pIter = taosHashIterate(pStore->uidHash, pIter);
- }
- return TSDB_CODE_SUCCESS;
-}
-
-static int32_t tsdbProcessSubmitReq(STsdb *pTsdb, int64_t version, void *pReq) {
- if (!pReq) {
- terrno = TSDB_CODE_INVALID_PTR;
- return TSDB_CODE_FAILED;
- }
-
- SSubmitReq *pSubmitReq = (SSubmitReq *)pReq;
-
- if (tsdbInsertData(pTsdb, version, pSubmitReq, NULL) < 0) {
- return TSDB_CODE_FAILED;
- }
-
- return TSDB_CODE_SUCCESS;
-}
-
-static int32_t tsdbFetchSubmitReqSuids(SSubmitReq *pMsg, STbUidStore *pStore) {
- ASSERT(pMsg != NULL);
- SSubmitMsgIter msgIter = {0};
- SSubmitBlk *pBlock = NULL;
- SSubmitBlkIter blkIter = {0};
- STSRow *row = NULL;
-
- terrno = TSDB_CODE_SUCCESS;
-
- if (tInitSubmitMsgIter(pMsg, &msgIter) < 0) return -1;
- while (true) {
- if (tGetSubmitMsgNext(&msgIter, &pBlock) < 0) return -1;
-
- if (!pBlock) break;
- tsdbUidStorePut(pStore, msgIter.suid, NULL);
- pStore->uid = msgIter.uid; // TODO: remove, just for debugging
- }
-
- if (terrno != TSDB_CODE_SUCCESS) return -1;
- return 0;
-}
-
-static FORCE_INLINE int32_t tsdbExecuteRSmaImpl(STsdb *pTsdb, const void *pMsg, int32_t inputType,
- qTaskInfo_t *taskInfo, STSchema *pTSchema, tb_uid_t suid, tb_uid_t uid,
- int8_t level) {
- SArray *pResult = NULL;
-
- if (!taskInfo) {
- tsdbDebug("vgId:%d no qTaskInfo to execute rsma %" PRIi8 " task for suid:%" PRIu64, REPO_ID(pTsdb), level, suid);
- return TSDB_CODE_SUCCESS;
- }
-
- tsdbDebug("vgId:%d execute rsma %" PRIi8 " task for qTaskInfo:%p suid:%" PRIu64, REPO_ID(pTsdb), level, taskInfo,
- suid);
-
- qSetStreamInput(taskInfo, pMsg, inputType, false);
- while (1) {
- SSDataBlock *output = NULL;
- uint64_t ts;
- if (qExecTask(taskInfo, &output, &ts) < 0) {
- ASSERT(false);
- }
- if (!output) {
- break;
- }
- if (!pResult) {
- pResult = taosArrayInit(0, sizeof(SSDataBlock));
- if (!pResult) {
- terrno = TSDB_CODE_OUT_OF_MEMORY;
- return TSDB_CODE_FAILED;
- }
- }
-
- taosArrayPush(pResult, output);
- }
-
- if (taosArrayGetSize(pResult) > 0) {
- blockDebugShowData(pResult);
- STsdb *sinkTsdb = (level == TSDB_RETENTION_L1 ? pTsdb->pVnode->pRSma1 : pTsdb->pVnode->pRSma2);
- SSubmitReq *pReq = NULL;
- if (buildSubmitReqFromDataBlock(&pReq, pResult, pTSchema, TD_VID(pTsdb->pVnode), suid) != 0) {
- taosArrayDestroy(pResult);
- return TSDB_CODE_FAILED;
- }
- if (tsdbProcessSubmitReq(sinkTsdb, INT64_MAX, pReq) != 0) {
- taosArrayDestroy(pResult);
- taosMemoryFreeClear(pReq);
- return TSDB_CODE_FAILED;
- }
- taosMemoryFreeClear(pReq);
- } else {
- tsdbWarn("vgId:%d no rsma % " PRIi8 " data generated since %s", REPO_ID(pTsdb), level, tstrerror(terrno));
- }
-
- taosArrayDestroy(pResult);
-
- return TSDB_CODE_SUCCESS;
-}
-
-static int32_t tsdbExecuteRSma(STsdb *pTsdb, const void *pMsg, int32_t inputType, tb_uid_t suid, tb_uid_t uid) {
- SSmaEnv *pEnv = REPO_RSMA_ENV(pTsdb);
- if (!pEnv) {
- // only applicable when rsma env exists
- return TSDB_CODE_SUCCESS;
- }
-
- ASSERT(uid != 0); // TODO: remove later
-
- SSmaStat *pStat = SMA_ENV_STAT(pEnv);
- SRSmaInfo *pRSmaInfo = NULL;
-
- pRSmaInfo = taosHashGet(SMA_STAT_INFO_HASH(pStat), &suid, sizeof(tb_uid_t));
-
- if (!pRSmaInfo || !(pRSmaInfo = *(SRSmaInfo **)pRSmaInfo)) {
- tsdbDebug("vgId:%d no rsma info for suid:%" PRIu64, REPO_ID(pTsdb), suid);
- return TSDB_CODE_SUCCESS;
- }
- if (!pRSmaInfo->taskInfo[0]) {
- tsdbDebug("vgId:%d no rsma qTaskInfo for suid:%" PRIu64, REPO_ID(pTsdb), suid);
- return TSDB_CODE_SUCCESS;
- }
-
- if (inputType == STREAM_DATA_TYPE_SUBMIT_BLOCK) {
- // TODO: use the proper schema instead of 1, and cache STSchema in cache
- STSchema *pTSchema = metaGetTbTSchema(pTsdb->pVnode->pMeta, suid, 1);
- if (!pTSchema) {
- terrno = TSDB_CODE_TDB_IVD_TB_SCHEMA_VERSION;
- return TSDB_CODE_FAILED;
- }
- tsdbExecuteRSmaImpl(pTsdb, pMsg, inputType, pRSmaInfo->taskInfo[0], pTSchema, suid, uid, TSDB_RETENTION_L1);
- tsdbExecuteRSmaImpl(pTsdb, pMsg, inputType, pRSmaInfo->taskInfo[1], pTSchema, suid, uid, TSDB_RETENTION_L2);
- taosMemoryFree(pTSchema);
- }
-
- return TSDB_CODE_SUCCESS;
-}
-
-int32_t tsdbTriggerRSma(STsdb *pTsdb, void *pMsg, int32_t inputType) {
- SSmaEnv *pEnv = REPO_RSMA_ENV(pTsdb);
- if (!pEnv) {
- // only applicable when rsma env exists
- return TSDB_CODE_SUCCESS;
- }
-
- if (inputType == STREAM_DATA_TYPE_SUBMIT_BLOCK) {
- STbUidStore uidStore = {0};
- tsdbFetchSubmitReqSuids(pMsg, &uidStore);
-
- if (uidStore.suid != 0) {
- tsdbExecuteRSma(pTsdb, pMsg, inputType, uidStore.suid, uidStore.uid);
-
- void *pIter = taosHashIterate(uidStore.uidHash, NULL);
- while (pIter) {
- tb_uid_t *pTbSuid = (tb_uid_t *)taosHashGetKey(pIter, NULL);
- tsdbExecuteRSma(pTsdb, pMsg, inputType, *pTbSuid, 0);
- pIter = taosHashIterate(uidStore.uidHash, pIter);
- }
-
- tsdbUidStoreDestory(&uidStore);
- }
- }
- return TSDB_CODE_SUCCESS;
-}
-
-#if 0
-/**
- * @brief Get the start TS key of the last data block of one interval/sliding.
- *
- * @param pTsdb
- * @param param
- * @param result
- * @return int32_t
- * 1) Return 0 and fill the result if the check procedure is normal;
- * 2) Return -1 if error occurs during the check procedure.
- */
-int32_t tsdbGetTSmaStatus(STsdb *pTsdb, void *smaIndex, void *result) {
- const char *procedure = "";
- if (strncmp(procedure, "get the start TS key of the last data block", 100) != 0) {
- return -1;
- }
- // fill the result
- return TSDB_CODE_SUCCESS;
-}
-
-/**
- * @brief Remove the tSma data files related to param between pWin.
- *
- * @param pTsdb
- * @param param
- * @param pWin
- * @return int32_t
- */
-int32_t tsdbRemoveTSmaData(STsdb *pTsdb, void *smaIndex, STimeWindow *pWin) {
- // for ("tSmaFiles of param-interval-sliding between pWin") {
- // // remove the tSmaFile
- // }
- return TSDB_CODE_SUCCESS;
-}
-#endif
-
-// TODO: Who is responsible for resource allocate and release?
-int32_t tsdbInsertTSmaData(STsdb *pTsdb, int64_t indexUid, const char *msg) {
- int32_t code = TSDB_CODE_SUCCESS;
- if ((code = tsdbInsertTSmaDataImpl(pTsdb, indexUid, msg)) < 0) {
- tsdbWarn("vgId:%d insert tSma data failed since %s", REPO_ID(pTsdb), tstrerror(terrno));
- }
- // TODO: destroy SSDataBlocks(msg)
- return code;
-}
-
-int32_t tsdbUpdateSmaWindow(STsdb *pTsdb, SSubmitReq *pMsg, int64_t version) {
- int32_t code = TSDB_CODE_SUCCESS;
- if ((code = tsdbUpdateExpiredWindowImpl(pTsdb, pMsg, version)) < 0) {
- tsdbWarn("vgId:%d update expired sma window failed since %s", REPO_ID(pTsdb), tstrerror(terrno));
- }
- return code;
-}
-
-int32_t tsdbInsertRSmaData(STsdb *pTsdb, char *msg) {
- int32_t code = TSDB_CODE_SUCCESS;
- if ((code = tsdbInsertRSmaDataImpl(pTsdb, msg)) < 0) {
- tsdbWarn("vgId:%d insert rSma data failed since %s", REPO_ID(pTsdb), tstrerror(terrno));
- }
- return code;
-}
-
-int32_t tsdbGetTSmaData(STsdb *pTsdb, char *pData, int64_t indexUid, TSKEY querySKey, int32_t nMaxResult) {
- int32_t code = TSDB_CODE_SUCCESS;
- if ((code = tsdbGetTSmaDataImpl(pTsdb, pData, indexUid, querySKey, nMaxResult)) < 0) {
- tsdbWarn("vgId:%d get tSma data failed since %s", REPO_ID(pTsdb), tstrerror(terrno));
- }
- return code;
-}
-
-int32_t tsdbDropTSmaData(STsdb *pTsdb, int64_t indexUid) {
- int32_t code = TSDB_CODE_SUCCESS;
- if ((code = tsdbDropTSmaDataImpl(pTsdb, indexUid)) < 0) {
- tsdbWarn("vgId:%d drop tSma data failed since %s", REPO_ID(pTsdb), tstrerror(terrno));
- }
- return code;
-}
\ No newline at end of file
diff --git a/source/dnode/vnode/src/tsdb/tsdbTDBImpl.c b/source/dnode/vnode/src/tsdb/tsdbTDBImpl.c
deleted file mode 100644
index a553f32bee..0000000000
--- a/source/dnode/vnode/src/tsdb/tsdbTDBImpl.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (c) 2019 TAOS Data, Inc.
- *
- * This program is free software: you can use, redistribute, and/or modify
- * it under the terms of the GNU Affero General Public License, version 3
- * or later ("AGPL"), as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-#define ALLOW_FORBID_FUNC
-
-#include "tsdb.h"
-
-int32_t tsdbOpenDBEnv(TDB **ppEnv, const char *path) {
- int ret = 0;
-
- if (path == NULL) return -1;
-
- ret = tdbOpen(path, 4096, 256, ppEnv); // use as param
-
- if (ret != 0) {
- tsdbError("Failed to create tsdb db env, ret = %d", ret);
- return -1;
- }
-
- return 0;
-}
-
-int32_t tsdbCloseDBEnv(TDB *pEnv) { return tdbClose(pEnv); }
-
-static inline int tsdbSmaKeyCmpr(const void *arg1, int len1, const void *arg2, int len2) {
- const SSmaKey *pKey1 = (const SSmaKey *)arg1;
- const SSmaKey *pKey2 = (const SSmaKey *)arg2;
-
- ASSERT(len1 == len2 && len1 == sizeof(SSmaKey));
-
- if (pKey1->skey < pKey2->skey) {
- return -1;
- } else if (pKey1->skey > pKey2->skey) {
- return 1;
- }
- if (pKey1->groupId < pKey2->groupId) {
- return -1;
- } else if (pKey1->groupId > pKey2->groupId) {
- return 1;
- }
-
- return 0;
-}
-
-static int32_t tsdbOpenDBDb(TTB **ppDB, TDB *pEnv, const char *pFName) {
- int ret;
- tdb_cmpr_fn_t compFunc;
-
- // Create a database
- compFunc = tsdbSmaKeyCmpr;
- ret = tdbTbOpen(pFName, -1, -1, compFunc, pEnv, ppDB);
-
- return 0;
-}
-
-static int32_t tsdbCloseDBDb(TTB *pDB) { return tdbTbClose(pDB); }
-
-int32_t tsdbOpenDBF(TDB *pEnv, SDBFile *pDBF) {
- // TEnv is shared by a group of SDBFile
- if (!pEnv || !pDBF) {
- terrno = TSDB_CODE_INVALID_PTR;
- return -1;
- }
-
- // Open DBF
- if (tsdbOpenDBDb(&(pDBF->pDB), pEnv, pDBF->path) < 0) {
- terrno = TSDB_CODE_TDB_INIT_FAILED;
- tsdbCloseDBDb(pDBF->pDB);
- return -1;
- }
-
- return 0;
-}
-
-int32_t tsdbCloseDBF(SDBFile *pDBF) {
- int32_t ret = 0;
- if (pDBF->pDB) {
- ret = tsdbCloseDBDb(pDBF->pDB);
- pDBF->pDB = NULL;
- }
- taosMemoryFreeClear(pDBF->path);
- return ret;
-}
-
-int32_t tsdbSaveSmaToDB(SDBFile *pDBF, void *pKey, int32_t keyLen, void *pVal, int32_t valLen, TXN *txn) {
- int32_t ret;
-
- ret = tdbTbInsert(pDBF->pDB, pKey, keyLen, pVal, valLen, txn);
- if (ret < 0) {
- tsdbError("Failed to create insert sma data into db, ret = %d", ret);
- return -1;
- }
-
- return 0;
-}
-
-void *tsdbGetSmaDataByKey(SDBFile *pDBF, const void *pKey, int32_t keyLen, int32_t *valLen) {
- void *pVal = NULL;
- int ret;
-
- ret = tdbTbGet(pDBF->pDB, pKey, keyLen, &pVal, valLen);
-
- if (ret < 0) {
- tsdbError("Failed to get sma data from db, ret = %d", ret);
- return NULL;
- }
-
- ASSERT(*valLen >= 0);
-
- // TODO: lock?
- // TODO: Would the key/value be destoryed during return the data?
- // TODO: How about the key is updated while value length is changed? The original value buffer would be freed
- // automatically?
-
- return pVal;
-}
\ No newline at end of file
diff --git a/source/dnode/vnode/src/vnd/vnodeCfg.c b/source/dnode/vnode/src/vnd/vnodeCfg.c
index 56cc3d6374..e8fa2ed3c1 100644
--- a/source/dnode/vnode/src/vnd/vnodeCfg.c
+++ b/source/dnode/vnode/src/vnd/vnodeCfg.c
@@ -57,6 +57,7 @@ int vnodeEncodeConfig(const void *pObj, SJson *pJson) {
if (tjsonAddIntegerToObject(pJson, "isHeap", pCfg->isHeap) < 0) return -1;
if (tjsonAddIntegerToObject(pJson, "isWeak", pCfg->isWeak) < 0) return -1;
if (tjsonAddIntegerToObject(pJson, "isTsma", pCfg->isTsma) < 0) return -1;
+ if (tjsonAddIntegerToObject(pJson, "isRsma", pCfg->isRsma) < 0) return -1;
if (tjsonAddIntegerToObject(pJson, "precision", pCfg->tsdbCfg.precision) < 0) return -1;
if (tjsonAddIntegerToObject(pJson, "update", pCfg->tsdbCfg.update) < 0) return -1;
if (tjsonAddIntegerToObject(pJson, "compression", pCfg->tsdbCfg.compression) < 0) return -1;
@@ -133,6 +134,8 @@ int vnodeDecodeConfig(const SJson *pJson, void *pObj) {
if(code < 0) return -1;
tjsonGetNumberValue(pJson, "isTsma", pCfg->isTsma, code);
if(code < 0) return -1;
+ tjsonGetNumberValue(pJson, "isRsma", pCfg->isRsma, code);
+ if(code < 0) return -1;
tjsonGetNumberValue(pJson, "precision", pCfg->tsdbCfg.precision, code);
if(code < 0) return -1;
tjsonGetNumberValue(pJson, "update", pCfg->tsdbCfg.update, code);
diff --git a/source/dnode/vnode/src/vnd/vnodeCommit.c b/source/dnode/vnode/src/vnd/vnodeCommit.c
index b4fbd01c63..a0db3cfe2d 100644
--- a/source/dnode/vnode/src/vnd/vnodeCommit.c
+++ b/source/dnode/vnode/src/vnd/vnodeCommit.c
@@ -230,7 +230,7 @@ int vnodeCommit(SVnode *pVnode) {
return -1;
}
- if(vnodeIsRollup(pVnode)) {
+ if (VND_IS_RSMA(pVnode)) {
if (tsdbCommit(VND_RSMA0(pVnode)) < 0) {
ASSERT(0);
return -1;
@@ -250,7 +250,6 @@ int vnodeCommit(SVnode *pVnode) {
}
}
-
if (tqCommit(pVnode->pTq) < 0) {
ASSERT(0);
return -1;
diff --git a/source/dnode/vnode/src/vnd/vnodeModule.c b/source/dnode/vnode/src/vnd/vnodeModule.c
index efae74b55a..d0aede145e 100644
--- a/source/dnode/vnode/src/vnd/vnodeModule.c
+++ b/source/dnode/vnode/src/vnd/vnodeModule.c
@@ -69,6 +69,9 @@ int vnodeInit(int nthreads) {
if (walInit() < 0) {
return -1;
}
+ if (tqInit() < 0) {
+ return -1;
+ }
return 0;
}
@@ -94,6 +97,9 @@ void vnodeCleanup() {
taosMemoryFreeClear(vnodeGlobal.threads);
taosThreadCondDestroy(&(vnodeGlobal.hasTask));
taosThreadMutexDestroy(&(vnodeGlobal.mutex));
+
+ walCleanUp();
+ tqCleanUp();
}
int vnodeScheduleTask(int (*execute)(void*), void* arg) {
@@ -155,4 +161,4 @@ static void* loop(void* arg) {
}
return NULL;
-}
\ No newline at end of file
+}
diff --git a/source/dnode/vnode/src/vnd/vnodeOpen.c b/source/dnode/vnode/src/vnd/vnodeOpen.c
index 178ef28e5d..7a26c16e4b 100644
--- a/source/dnode/vnode/src/vnd/vnodeOpen.c
+++ b/source/dnode/vnode/src/vnd/vnodeOpen.c
@@ -97,7 +97,7 @@ SVnode *vnodeOpen(const char *path, STfs *pTfs, SMsgCb msgCb) {
}
// open tsdb
- if (!vnodeIsRollup(pVnode) && tsdbOpen(pVnode, &VND_TSDB(pVnode), VNODE_TSDB_DIR, NULL) < 0) {
+ if (!VND_IS_RSMA(pVnode) && tsdbOpen(pVnode, &VND_TSDB(pVnode), VNODE_TSDB_DIR, NULL) < 0) {
vError("vgId:%d failed to open vnode tsdb since %s", TD_VID(pVnode), tstrerror(terrno));
goto _err;
}
@@ -189,4 +189,4 @@ void vnodeStop(SVnode *pVnode) {}
int64_t vnodeGetSyncHandle(SVnode *pVnode) { return pVnode->sync; }
-void vnodeGetSnapshot(SVnode *pVnode, SSnapshot *pSnapshot) { pSnapshot->lastApplyIndex = pVnode->state.committed; }
\ No newline at end of file
+void vnodeGetSnapshot(SVnode *pVnode, SSnapshot *pSnapshot) { pSnapshot->lastApplyIndex = pVnode->state.committed; }
diff --git a/source/dnode/vnode/src/vnd/vnodeSvr.c b/source/dnode/vnode/src/vnd/vnodeSvr.c
index 3ab5789eae..ab879c5dbb 100644
--- a/source/dnode/vnode/src/vnd/vnodeSvr.c
+++ b/source/dnode/vnode/src/vnd/vnodeSvr.c
@@ -22,7 +22,7 @@ static int vnodeProcessCreateTbReq(SVnode *pVnode, int64_t version, void *pReq,
static int vnodeProcessAlterTbReq(SVnode *pVnode, int64_t version, void *pReq, int32_t len, SRpcMsg *pRsp);
static int vnodeProcessDropTbReq(SVnode *pVnode, int64_t version, void *pReq, int32_t len, SRpcMsg *pRsp);
static int vnodeProcessSubmitReq(SVnode *pVnode, int64_t version, void *pReq, int32_t len, SRpcMsg *pRsp);
-static int vnodeProcessCreateTSmaReq(SVnode *pVnode, int64_t version, void *pReq, int len, SRpcMsg *pRsp);
+static int vnodeProcessCreateTSmaReq(SVnode *pVnode, int64_t version, void *pReq, int32_t len, SRpcMsg *pRsp);
int32_t vnodePreprocessReq(SVnode *pVnode, SRpcMsg *pMsg) {
SDecoder dc = {0};
@@ -88,6 +88,9 @@ int32_t vnodePreprocessReq(SVnode *pVnode, SRpcMsg *pMsg) {
}
} break;
+ case TDMT_VND_ALTER_REPLICA: {
+ vnodeSyncAlter(pVnode, pMsg);
+ } break;
default:
break;
}
@@ -154,7 +157,7 @@ int vnodeProcessWriteReq(SVnode *pVnode, SRpcMsg *pMsg, int64_t version, SRpcMsg
pMsg->contLen - sizeof(SMsgHead)) < 0) {
}
} break;
- case TDMT_VND_ALTER_VNODE:
+ case TDMT_VND_ALTER_CONFIG:
break;
default:
ASSERT(0);
@@ -789,28 +792,30 @@ _exit:
// TODO: the partial success scenario and the error case
// TODO: refactor
- if ((terrno == TSDB_CODE_SUCCESS || terrno == TSDB_CODE_TDB_TABLE_ALREADY_EXIST) &&
- (pRsp->code == TSDB_CODE_SUCCESS)) {
+ if ((terrno == TSDB_CODE_SUCCESS) && (pRsp->code == TSDB_CODE_SUCCESS)) {
tdProcessRSmaSubmit(pVnode->pSma, pReq, STREAM_DATA_TYPE_SUBMIT_BLOCK);
}
return 0;
}
-static int vnodeProcessCreateTSmaReq(SVnode *pVnode, int64_t version, void *pReq, int len, SRpcMsg *pRsp) {
+static int vnodeProcessCreateTSmaReq(SVnode *pVnode, int64_t version, void *pReq, int32_t len, SRpcMsg *pRsp) {
SVCreateTSmaReq req = {0};
SDecoder coder;
- pRsp->msgType = TDMT_VND_CREATE_SMA_RSP;
- pRsp->code = TSDB_CODE_SUCCESS;
- pRsp->pCont = NULL;
- pRsp->contLen = 0;
+ if (pRsp) {
+ pRsp->msgType = TDMT_VND_CREATE_SMA_RSP;
+ pRsp->code = TSDB_CODE_SUCCESS;
+ pRsp->pCont = NULL;
+ pRsp->contLen = 0;
+ }
// decode and process req
tDecoderInit(&coder, pReq, len);
if (tDecodeSVCreateTSmaReq(&coder, &req) < 0) {
- pRsp->code = terrno;
+ terrno = TSDB_CODE_MSG_DECODE_ERROR;
+ if (pRsp) pRsp->code = terrno;
goto _err;
}
@@ -818,18 +823,30 @@ static int vnodeProcessCreateTSmaReq(SVnode *pVnode, int64_t version, void *pReq
req.timezoneInt = tsTimezone;
if (tdProcessTSmaCreate(pVnode->pSma, version, (const char *)&req) < 0) {
- pRsp->code = terrno;
+ if (pRsp) pRsp->code = terrno;
goto _err;
}
tDecoderClear(&coder);
- vDebug("vgId:%d success to create tsma %s:%" PRIi64 " for table %" PRIi64, TD_VID(pVnode), req.indexName,
- req.indexUid, req.tableUid);
+ vDebug("vgId:%d success to create tsma %s:%" PRIi64 " version %" PRIi64 " for table %" PRIi64, TD_VID(pVnode),
+ req.indexName, req.indexUid, version, req.tableUid);
return 0;
_err:
tDecoderClear(&coder);
- vError("vgId:%d failed to create tsma %s:%" PRIi64 " for table %" PRIi64 " since %s", TD_VID(pVnode), req.indexName,
- req.indexUid, req.tableUid, terrstr(terrno));
+ vError("vgId:%d failed to create tsma %s:%" PRIi64 " version %" PRIi64 "for table %" PRIi64 " since %s",
+ TD_VID(pVnode), req.indexName, req.indexUid, version, req.tableUid, terrstr(terrno));
return -1;
}
+
+/**
+ * @brief specific for smaDstVnode
+ *
+ * @param pVnode
+ * @param pCont
+ * @param contLen
+ * @return int32_t
+ */
+int32_t vnodeProcessCreateTSma(SVnode *pVnode, void *pCont, uint32_t contLen) {
+ return vnodeProcessCreateTSmaReq(pVnode, 1, pCont, contLen, NULL);
+}
diff --git a/source/dnode/vnode/src/vnd/vnodeSync.c b/source/dnode/vnode/src/vnd/vnodeSync.c
index d146877853..8792fbbb0c 100644
--- a/source/dnode/vnode/src/vnd/vnodeSync.c
+++ b/source/dnode/vnode/src/vnd/vnodeSync.c
@@ -27,6 +27,7 @@ static int32_t vnodeSyncGetSnapshot(SSyncFSM *pFsm, SSnapshot *pSnapshot);
int32_t vnodeSyncOpen(SVnode *pVnode, char *path) {
SSyncInfo syncInfo = {
.vgId = pVnode->config.vgId,
+ .isStandBy = pVnode->config.standby,
.syncCfg = pVnode->config.syncCfg,
.pWal = pVnode->pWal,
.msgcb = NULL,
@@ -49,28 +50,72 @@ int32_t vnodeSyncOpen(SVnode *pVnode, char *path) {
return 0;
}
+void vnodeSyncAlter(SVnode *pVnode, SRpcMsg *pMsg) {
+ SAlterVnodeReq req = {0};
+ if (tDeserializeSAlterVnodeReq((char *)pMsg->pCont + sizeof(SMsgHead), pMsg->contLen - sizeof(SMsgHead), &req) != 0) {
+ terrno = TSDB_CODE_INVALID_MSG;
+ vError("vgId:%d, failed to alter replica since %s", TD_VID(pVnode), terrstr());
+ SRpcMsg rsp = {.info = pMsg->info, .code = terrno};
+ tmsgSendRsp(&rsp);
+ }
+
+ vInfo("vgId:%d, start to alter vnode replica to %d", TD_VID(pVnode), req.replica);
+ SSyncCfg cfg = {.replicaNum = req.replica, .myIndex = req.selfIndex};
+ for (int32_t r = 0; r < req.replica; ++r) {
+ SNodeInfo *pNode = &cfg.nodeInfo[r];
+ tstrncpy(pNode->nodeFqdn, req.replicas[r].fqdn, sizeof(pNode->nodeFqdn));
+ pNode->nodePort = req.replicas[r].port;
+ vInfo("vgId:%d, replica:%d %s:%u", TD_VID(pVnode), r, pNode->nodeFqdn, pNode->nodePort);
+ }
+
+ if (syncReconfig(pVnode->sync, &cfg) != 0) {
+ vError("vgId:%d, failed to propose sync reconfig since %s", TD_VID(pVnode), terrstr());
+ SRpcMsg rsp = {.info = pMsg->info, .code = terrno};
+ tmsgSendRsp(&rsp);
+ }
+}
+
void vnodeSyncStart(SVnode *pVnode) {
syncSetMsgCb(pVnode->sync, &pVnode->msgCb);
- syncStart(pVnode->sync);
+ if (pVnode->config.standby) {
+ syncStartStandBy(pVnode->sync);
+ } else {
+ syncStart(pVnode->sync);
+ }
}
void vnodeSyncClose(SVnode *pVnode) { syncStop(pVnode->sync); }
-int32_t vnodeSyncEqMsg(const SMsgCb *msgcb, SRpcMsg *pMsg) {
+int32_t vnodeSyncEqMsg(const SMsgCb *msgcb, SRpcMsg *pMsg) {
int32_t code = tmsgPutToQueue(msgcb, SYNC_QUEUE, pMsg);
if (code != 0) {
rpcFreeCont(pMsg->pCont);
+ pMsg->pCont = NULL;
}
return code;
}
-int32_t vnodeSyncSendMsg(const SEpSet *pEpSet, SRpcMsg *pMsg) { return tmsgSendReq(pEpSet, pMsg); }
+int32_t vnodeSyncSendMsg(const SEpSet *pEpSet, SRpcMsg *pMsg) {
+ int32_t code = tmsgSendReq(pEpSet, pMsg);
+ if (code != 0) {
+ rpcFreeCont(pMsg->pCont);
+ pMsg->pCont = NULL;
+ }
+ return code;
+}
int32_t vnodeSyncGetSnapshot(SSyncFSM *pFsm, SSnapshot *pSnapshot) {
vnodeGetSnapshot(pFsm->data, pSnapshot);
return 0;
}
+void vnodeSyncReconfig(struct SSyncFSM *pFsm, SSyncCfg newCfg, SReConfigCbMeta cbMeta) {
+ SVnode *pVnode = pFsm->data;
+ vInfo("vgId:%d, sync reconfig is confirmed", TD_VID(pVnode));
+
+ // todo rpc response here
+}
+
void vnodeSyncCommitMsg(SSyncFSM *pFsm, const SRpcMsg *pMsg, SFsmCbMeta cbMeta) {
SyncIndex beginIndex = SYNC_INDEX_INVALID;
if (pFsm->FpGetSnapshot != NULL) {
@@ -87,20 +132,12 @@ void vnodeSyncCommitMsg(SSyncFSM *pFsm, const SRpcMsg *pMsg, SFsmCbMeta cbMeta)
pFsm, cbMeta.index, cbMeta.isWeak, cbMeta.code, cbMeta.state, syncUtilState2String(cbMeta.state), beginIndex);
syncRpcMsgLog2(logBuf, (SRpcMsg *)pMsg);
- SVnode *pVnode = (SVnode *)(pFsm->data);
+ SVnode *pVnode = pFsm->data;
SyncApplyMsg *pSyncApplyMsg = syncApplyMsgBuild2(pMsg, pVnode->config.vgId, &cbMeta);
SRpcMsg applyMsg;
syncApplyMsg2RpcMsg(pSyncApplyMsg, &applyMsg);
syncApplyMsgDestroy(pSyncApplyMsg);
- /*
- SRpcMsg applyMsg;
- applyMsg = *pMsg;
- applyMsg.pCont = rpcMallocCont(applyMsg.contLen);
- assert(applyMsg.contLen == pMsg->contLen);
- memcpy(applyMsg.pCont, pMsg->pCont, applyMsg.contLen);
- */
-
// recover handle for response
SRpcMsg saveRpcMsg;
int32_t ret = syncGetAndDelRespRpc(pVnode->sync, cbMeta.seqNum, &saveRpcMsg);
@@ -142,14 +179,13 @@ void vnodeSyncRollBackMsg(SSyncFSM *pFsm, const SRpcMsg *pMsg, SFsmCbMeta cbMeta
SSyncFSM *vnodeSyncMakeFsm(SVnode *pVnode) {
SSyncFSM *pFsm = taosMemoryCalloc(1, sizeof(SSyncFSM));
- memset(pFsm, 0, sizeof(*pFsm));
pFsm->data = pVnode;
pFsm->FpCommitCb = vnodeSyncCommitMsg;
pFsm->FpPreCommitCb = vnodeSyncPreCommitMsg;
pFsm->FpRollBackCb = vnodeSyncRollBackMsg;
pFsm->FpGetSnapshot = vnodeSyncGetSnapshot;
pFsm->FpRestoreFinishCb = NULL;
- pFsm->FpReConfigCb = NULL;
+ pFsm->FpReConfigCb = vnodeSyncReconfig;
return pFsm;
}
\ No newline at end of file
diff --git a/source/dnode/vnode/test/tsdbSmaTest.cpp b/source/dnode/vnode/test/tsdbSmaTest.cpp
index ab617cb186..4d2741f751 100644
--- a/source/dnode/vnode/test/tsdbSmaTest.cpp
+++ b/source/dnode/vnode/test/tsdbSmaTest.cpp
@@ -368,7 +368,7 @@ TEST(testCase, tSma_Data_Insert_Query_Test) {
SDiskCfg pDisks = {0};
pDisks.level = 0;
pDisks.primary = 1;
- strncpy(pDisks.dir, "/var/lib/taos", TSDB_FILENAME_LEN);
+ strncpy(pDisks.dir, TD_DATA_DIR_PATH, TSDB_FILENAME_LEN);
int32_t numOfDisks = 1;
pTsdb->pTfs = tfsOpen(&pDisks, numOfDisks);
EXPECT_NE(pTsdb->pTfs, nullptr);
diff --git a/source/libs/catalog/test/catalogTests.cpp b/source/libs/catalog/test/catalogTests.cpp
index 5b720006c6..e4ae2c004f 100644
--- a/source/libs/catalog/test/catalogTests.cpp
+++ b/source/libs/catalog/test/catalogTests.cpp
@@ -137,7 +137,7 @@ void ctgTestInitLogFile() {
tsAsyncLog = 0;
qDebugFlag = 159;
- strcpy(tsLogDir, "/var/log/taos");
+ strcpy(tsLogDir, TD_LOG_DIR_PATH);
ctgdEnableDebug("api");
ctgdEnableDebug("meta");
diff --git a/source/libs/executor/src/scanoperator.c b/source/libs/executor/src/scanoperator.c
index a2966ee835..0e682682a1 100644
--- a/source/libs/executor/src/scanoperator.c
+++ b/source/libs/executor/src/scanoperator.c
@@ -313,29 +313,23 @@ void addTagPseudoColumnData(SReadHandle *pHandle, SExprInfo* pPseudoExpr, int32_
if (fmIsScanPseudoColumnFunc(functionId)) {
setTbNameColData(pHandle->meta, pBlock, pColInfoData, functionId);
} else { // these are tags
- const char* p = NULL;
- if (pColInfoData->info.type == TSDB_DATA_TYPE_JSON) {
- const uint8_t* tmp = mr.me.ctbEntry.pTags;
+ STagVal tagVal = {0};
+ tagVal.cid = pExpr->base.pParam[0].pCol->colId;
+ const char *p = metaGetTableTagVal(&mr.me, pColInfoData->info.type, &tagVal);
- char* data = taosMemoryCalloc(kvRowLen(tmp) + 1, 1);
- if (data == NULL) {
- metaReaderClear(&mr);
- qError("doTagScan calloc error:%d", kvRowLen(tmp) + 1);
- return;
- }
-
- *data = TSDB_DATA_TYPE_JSON;
- memcpy(data + 1, tmp, kvRowLen(tmp));
- p = data;
- } else {
- p = metaGetTableTagVal(&mr.me, pExpr->base.pParam[0].pCol->colId);
+ char *data = NULL;
+ if(pColInfoData->info.type != TSDB_DATA_TYPE_JSON && p != NULL){
+ data = tTagValToData((const STagVal *)p, false);
+ }else {
+ data = (char*)p;
}
for (int32_t i = 0; i < pBlock->info.rows; ++i) {
- colDataAppend(pColInfoData, i, p, (p == NULL));
+ colDataAppend(pColInfoData, i, data, (data == NULL));
}
- if (pColInfoData->info.type == TSDB_DATA_TYPE_JSON) {
- taosMemoryFree((void*)p);
+ if (data && (pColInfoData->info.type != TSDB_DATA_TYPE_JSON) && p != NULL &&
+ IS_VAR_DATA_TYPE(((const STagVal*)p)->type)) {
+ taosMemoryFree(data);
}
}
}
@@ -1589,22 +1583,21 @@ static SSDataBlock* doTagScan(SOperatorInfo* pOperator) {
STR_TO_VARSTR(str, mr.me.name);
colDataAppend(pDst, count, str, false);
} else { // it is a tag value
- if (pDst->info.type == TSDB_DATA_TYPE_JSON) {
- const uint8_t* tmp = mr.me.ctbEntry.pTags;
- // TODO opt perf by realloc memory
- char* data = taosMemoryCalloc(kvRowLen(tmp) + 1, 1);
- if (data == NULL) {
- qError("%s failed to malloc memory, size:%d", GET_TASKID(pTaskInfo), kvRowLen(tmp) + 1);
- longjmp(pTaskInfo->env, TSDB_CODE_OUT_OF_MEMORY);
- }
+ STagVal val = {0};
+ val.cid = pExprInfo[j].base.pParam[0].pCol->colId;
+ const char* p = metaGetTableTagVal(&mr.me, pDst->info.type, &val);
- *data = TSDB_DATA_TYPE_JSON;
- memcpy(data + 1, tmp, kvRowLen(tmp));
- colDataAppend(pDst, count, data, false);
+ char *data = NULL;
+ if(pDst->info.type != TSDB_DATA_TYPE_JSON && p != NULL){
+ data = tTagValToData((const STagVal *)p, false);
+ }else {
+ data = (char*)p;
+ }
+ colDataAppend(pDst, count, data, (data == NULL));
+
+ if(pDst->info.type != TSDB_DATA_TYPE_JSON && p != NULL
+ && IS_VAR_DATA_TYPE(((const STagVal *)p)->type) && data != NULL){
taosMemoryFree(data);
- } else {
- const char* p = metaGetTableTagVal(&mr.me, pExprInfo[j].base.pParam[0].pCol->colId);
- colDataAppend(pDst, count, p, (p == NULL));
}
}
}
@@ -1634,8 +1627,8 @@ static void destroyTagScanOperatorInfo(void* param, int32_t numOfOutput) {
}
SOperatorInfo* createTagScanOperatorInfo(SReadHandle* pReadHandle, SExprInfo* pExpr, int32_t numOfOutput,
- SSDataBlock* pResBlock, SArray* pColMatchInfo,
- STableListInfo* pTableListInfo, SExecTaskInfo* pTaskInfo) {
+ SSDataBlock* pResBlock, SArray* pColMatchInfo, STableListInfo* pTableListInfo,
+ SExecTaskInfo* pTaskInfo) {
STagScanInfo* pInfo = taosMemoryCalloc(1, sizeof(STagScanInfo));
SOperatorInfo* pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
if (pInfo == NULL || pOperator == NULL) {
diff --git a/source/libs/function/inc/builtins.h b/source/libs/function/inc/builtins.h
index 3bd0f35bf5..bc91875006 100644
--- a/source/libs/function/inc/builtins.h
+++ b/source/libs/function/inc/builtins.h
@@ -26,22 +26,24 @@ typedef int32_t (*FTranslateFunc)(SFunctionNode* pFunc, char* pErrBuf, int32_t l
typedef EFuncDataRequired (*FFuncDataRequired)(SFunctionNode* pFunc, STimeWindow* pTimeWindow);
typedef struct SBuiltinFuncDefinition {
- char name[FUNCTION_NAME_MAX_LENGTH];
- EFunctionType type;
- uint64_t classification;
- FTranslateFunc translateFunc;
- FFuncDataRequired dataRequiredFunc;
- FExecGetEnv getEnvFunc;
- FExecInit initFunc;
- FExecProcess processFunc;
+ const char* name;
+ EFunctionType type;
+ uint64_t classification;
+ FTranslateFunc translateFunc;
+ FFuncDataRequired dataRequiredFunc;
+ FExecGetEnv getEnvFunc;
+ FExecInit initFunc;
+ FExecProcess processFunc;
FScalarExecProcess sprocessFunc;
- FExecFinalize finalizeFunc;
- FExecProcess invertFunc;
- FExecCombine combineFunc;
+ FExecFinalize finalizeFunc;
+ FExecProcess invertFunc;
+ FExecCombine combineFunc;
+ const char* pPartialFunc;
+ const char* pMergeFunc;
} SBuiltinFuncDefinition;
extern const SBuiltinFuncDefinition funcMgtBuiltins[];
-extern const int funcMgtBuiltinsNum;
+extern const int funcMgtBuiltinsNum;
#ifdef __cplusplus
}
diff --git a/source/libs/function/src/builtins.c b/source/libs/function/src/builtins.c
index add94cb83c..5560c9c1d5 100644
--- a/source/libs/function/src/builtins.c
+++ b/source/libs/function/src/builtins.c
@@ -103,6 +103,28 @@ static int32_t translateInOutStr(SFunctionNode* pFunc, char* pErrBuf, int32_t le
return TSDB_CODE_SUCCESS;
}
+static int32_t translateLogarithm(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
+ int32_t numOfParams = LIST_LENGTH(pFunc->pParameterList);
+ if (1 != numOfParams && 2 != numOfParams) {
+ return invaildFuncParaNumErrMsg(pErrBuf, len, pFunc->functionName);
+ }
+
+ uint8_t para1Type = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 0))->resType.type;
+ if (!IS_NUMERIC_TYPE(para1Type)) {
+ return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
+ }
+
+ if (2 == numOfParams) {
+ uint8_t para2Type = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 1))->resType.type;
+ if (!IS_NUMERIC_TYPE(para2Type)) {
+ return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
+ }
+ }
+
+ pFunc->node.resType = (SDataType){.bytes = tDataTypes[TSDB_DATA_TYPE_DOUBLE].bytes, .type = TSDB_DATA_TYPE_DOUBLE};
+ return TSDB_CODE_SUCCESS;
+}
+
static int32_t translateCount(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
if (1 != LIST_LENGTH(pFunc->pParameterList)) {
return invaildFuncParaNumErrMsg(pErrBuf, len, pFunc->functionName);
@@ -156,14 +178,14 @@ static int32_t translatePercentile(SFunctionNode* pFunc, char* pErrBuf, int32_t
return invaildFuncParaNumErrMsg(pErrBuf, len, pFunc->functionName);
}
- //param0
+ // param0
SNode* pParamNode0 = nodesListGetNode(pFunc->pParameterList, 0);
if (nodeType(pParamNode0) != QUERY_NODE_COLUMN) {
return buildFuncErrMsg(pErrBuf, len, TSDB_CODE_FUNC_FUNTION_ERROR,
"The first parameter of PERCENTILE function can only be column");
}
- //param1
+ // param1
SValueNode* pValue = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
if (pValue->datum.i < 0 || pValue->datum.i > 100) {
@@ -178,7 +200,7 @@ static int32_t translatePercentile(SFunctionNode* pFunc, char* pErrBuf, int32_t
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
}
- //set result type
+ // set result type
pFunc->node.resType = (SDataType){.bytes = tDataTypes[TSDB_DATA_TYPE_DOUBLE].bytes, .type = TSDB_DATA_TYPE_DOUBLE};
return TSDB_CODE_SUCCESS;
}
@@ -197,14 +219,14 @@ static int32_t translateApercentile(SFunctionNode* pFunc, char* pErrBuf, int32_t
return invaildFuncParaNumErrMsg(pErrBuf, len, pFunc->functionName);
}
- //param0
+ // param0
SNode* pParamNode0 = nodesListGetNode(pFunc->pParameterList, 0);
if (nodeType(pParamNode0) != QUERY_NODE_COLUMN) {
return buildFuncErrMsg(pErrBuf, len, TSDB_CODE_FUNC_FUNTION_ERROR,
"The first parameter of APERCENTILE function can only be column");
}
- //param1
+ // param1
SNode* pParamNode1 = nodesListGetNode(pFunc->pParameterList, 1);
if (nodeType(pParamNode1) != QUERY_NODE_VALUE) {
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
@@ -223,7 +245,7 @@ static int32_t translateApercentile(SFunctionNode* pFunc, char* pErrBuf, int32_t
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
}
- //param2
+ // param2
if (3 == numOfParams) {
uint8_t para3Type = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 2))->resType.type;
if (!IS_VAR_DATA_TYPE(para3Type)) {
@@ -263,14 +285,14 @@ static int32_t translateTop(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
}
- //param0
+ // param0
SNode* pParamNode0 = nodesListGetNode(pFunc->pParameterList, 0);
if (nodeType(pParamNode0) != QUERY_NODE_COLUMN) {
return buildFuncErrMsg(pErrBuf, len, TSDB_CODE_FUNC_FUNTION_ERROR,
"The first parameter of TOP/BOTTOM function can only be column");
}
- //param1
+ // param1
SNode* pParamNode1 = nodesListGetNode(pFunc->pParameterList, 1);
if (nodeType(pParamNode1) != QUERY_NODE_VALUE) {
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
@@ -287,7 +309,7 @@ static int32_t translateTop(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
pValue->notReserved = true;
- //set result type
+ // set result type
SDataType* pType = &((SExprNode*)nodesListGetNode(pFunc->pParameterList, 0))->resType;
pFunc->node.resType = (SDataType){.bytes = pType->bytes, .type = pType->type};
return TSDB_CODE_SUCCESS;
@@ -687,8 +709,8 @@ static int32_t translateTail(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
if (pValue->datum.i < ((i > 1) ? 0 : 1) || pValue->datum.i > 100) {
return buildFuncErrMsg(pErrBuf, len, TSDB_CODE_FUNC_FUNTION_ERROR,
- "TAIL function second parameter should be in range [1, 100], "
- "third parameter should be in range [0, 100]");
+ "TAIL function second parameter should be in range [1, 100], "
+ "third parameter should be in range [0, 100]");
}
pValue->notReserved = true;
@@ -749,7 +771,7 @@ static int32_t translateDiff(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
return invaildFuncParaNumErrMsg(pErrBuf, len, pFunc->functionName);
}
- //param0
+ // param0
SNode* pParamNode0 = nodesListGetNode(pFunc->pParameterList, 0);
if (nodeType(pParamNode0) != QUERY_NODE_COLUMN) {
return buildFuncErrMsg(pErrBuf, len, TSDB_CODE_FUNC_FUNTION_ERROR,
@@ -757,12 +779,11 @@ static int32_t translateDiff(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
}
uint8_t colType = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 0))->resType.type;
- if (!IS_SIGNED_NUMERIC_TYPE(colType) && !IS_FLOAT_TYPE(colType) &&
- TSDB_DATA_TYPE_BOOL != colType) {
+ if (!IS_SIGNED_NUMERIC_TYPE(colType) && !IS_FLOAT_TYPE(colType) && TSDB_DATA_TYPE_BOOL != colType) {
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
}
- //param1
+ // param1
if (numOfParams == 2) {
uint8_t paraType = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 1))->resType.type;
if (!IS_INTEGER_TYPE(paraType)) {
@@ -817,11 +838,20 @@ static int32_t translateConcatImpl(SFunctionNode* pFunc, char* pErrBuf, int32_t
int32_t resultBytes = 0;
int32_t sepBytes = 0;
+ //concat_ws separator should be constant string
+ if (hasSep) {
+ SNode* pPara = nodesListGetNode(pFunc->pParameterList, 0);
+ if (nodeType(pPara) != QUERY_NODE_VALUE) {
+ return buildFuncErrMsg(pErrBuf, len, TSDB_CODE_FUNC_FUNTION_ERROR,
+ "The first parameter of CONCAT_WS function can only be constant string");
+ }
+ }
+
/* For concat/concat_ws function, if params have NCHAR type, promote the final result to NCHAR */
for (int32_t i = 0; i < numOfParams; ++i) {
SNode* pPara = nodesListGetNode(pFunc->pParameterList, i);
uint8_t paraType = ((SExprNode*)pPara)->resType.type;
- if (!IS_VAR_DATA_TYPE(paraType)) {
+ if (!IS_VAR_DATA_TYPE(paraType) && TSDB_DATA_TYPE_NULL != paraType) {
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
}
if (TSDB_DATA_TYPE_NCHAR == paraType) {
@@ -880,7 +910,7 @@ static int32_t translateSubstr(SFunctionNode* pFunc, char* pErrBuf, int32_t len)
if (3 == numOfParams) {
SExprNode* p2 = (SExprNode*)nodesListGetNode(pFunc->pParameterList, 2);
- uint8_t para2Type = p2->resType.type;
+ uint8_t para2Type = p2->resType.type;
if (!IS_INTEGER_TYPE(para2Type)) {
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
}
@@ -921,16 +951,108 @@ static int32_t translateCast(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
return TSDB_CODE_SUCCESS;
}
+/* Following are valid ISO-8601 timezone format:
+ * 1 z/Z
+ * 2 ±hh:mm
+ * 3 ±hhmm
+ * 4 ±hh
+ *
+ */
+
+static bool validateTimezoneFormat(const SValueNode* pVal) {
+ if (TSDB_DATA_TYPE_BINARY != pVal->node.resType.type) {
+ return false;
+ }
+
+ char *tz = varDataVal(pVal->datum.p);
+ int32_t len = varDataLen(pVal->datum.p);
+
+ if (len == 0) {
+ return false;
+ } else if (len == 1 && (tz[0] == 'z' || tz[0] == 'Z')) {
+ return true;
+ } else if ((tz[0] == '+' || tz[0] == '-')) {
+ switch (len) {
+ case 3:
+ case 5: {
+ for (int32_t i = 1; i < len; ++i) {
+ if (!isdigit(tz[i])) {
+ return false;
+ }
+ }
+ break;
+ }
+ case 6: {
+ for (int32_t i = 1; i < len; ++i) {
+ if (i == 3) {
+ if (tz[i] != ':') {
+ return false;
+ }
+ continue;
+ }
+ if (!isdigit(tz[i])) {
+ return false;
+ }
+ }
+ break;
+ }
+ default: {
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void static addTimezoneParam(SNodeList* pList) {
+ char buf[6] = {0};
+ time_t t = taosTime(NULL);
+ struct tm *tmInfo = taosLocalTime(&t, NULL);
+ strftime(buf, sizeof(buf), "%z", tmInfo);
+ int32_t len = (int32_t)strlen(buf);
+
+ SValueNode* pVal = (SValueNode*)nodesMakeNode(QUERY_NODE_VALUE);
+ pVal->literal = strndup(buf, len);
+ pVal->isDuration =false;
+ pVal->translate = true;
+ pVal->node.resType.type = TSDB_DATA_TYPE_BINARY;
+ pVal->node.resType.bytes = len + VARSTR_HEADER_SIZE;
+ pVal->node.resType.precision = TSDB_TIME_PRECISION_MILLI;
+ pVal->datum.p = taosMemoryCalloc(1, len + VARSTR_HEADER_SIZE +1);
+ varDataSetLen(pVal->datum.p, len);
+ strncpy(varDataVal(pVal->datum.p), pVal->literal, len);
+
+ nodesListAppend(pList, pVal);
+}
+
static int32_t translateToIso8601(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
- if (1 != LIST_LENGTH(pFunc->pParameterList)) {
+ int32_t numOfParams = LIST_LENGTH(pFunc->pParameterList);
+ if (1 != numOfParams && 2 != numOfParams) {
return invaildFuncParaNumErrMsg(pErrBuf, len, pFunc->functionName);
}
+ //param0
uint8_t paraType = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 0))->resType.type;
if (!IS_INTEGER_TYPE(paraType) && TSDB_DATA_TYPE_TIMESTAMP != paraType) {
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
}
+ //param1
+ if (numOfParams == 2) {
+ SValueNode* pValue = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 1);
+
+ if (!validateTimezoneFormat(pValue)) {
+ return buildFuncErrMsg(pErrBuf, len, TSDB_CODE_FUNC_FUNTION_ERROR,
+ "Invalid timzone format");
+ }
+ } else { //add default client timezone
+ addTimezoneParam(pFunc->pParameterList);
+ }
+
+ //set result type
pFunc->node.resType = (SDataType){.bytes = 64, .type = TSDB_DATA_TYPE_BINARY};
return TSDB_CODE_SUCCESS;
}
@@ -1021,6 +1143,8 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
.finalizeFunc = functionFinalize,
.invertFunc = countInvertFunction,
.combineFunc = combineFunction,
+ // .pPartialFunc = "count",
+ // .pMergeFunc = "sum"
},
{
.name = "sum",
@@ -1302,7 +1426,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
.name = "log",
.type = FUNCTION_TYPE_LOG,
.classification = FUNC_MGT_SCALAR_FUNC,
- .translateFunc = translateIn2NumOutDou,
+ .translateFunc = translateLogarithm,
.getEnvFunc = NULL,
.initFunc = NULL,
.sprocessFunc = logFunction,
diff --git a/source/libs/function/src/functionMgt.c b/source/libs/function/src/functionMgt.c
index c2b325bc92..611ae8d81f 100644
--- a/source/libs/function/src/functionMgt.c
+++ b/source/libs/function/src/functionMgt.c
@@ -199,3 +199,81 @@ bool fmIsInvertible(int32_t funcId) {
}
return res;
}
+
+static SFunctionNode* createFunction(const char* pName, SNodeList* pParameterList) {
+ SFunctionNode* pFunc = nodesMakeNode(QUERY_NODE_FUNCTION);
+ if (NULL == pFunc) {
+ return NULL;
+ }
+ strcpy(pFunc->functionName, pName);
+ pFunc->pParameterList = pParameterList;
+ char msg[64] = {0};
+ if (TSDB_CODE_SUCCESS != fmGetFuncInfo(pFunc, msg, sizeof(msg))) {
+ nodesDestroyNode(pFunc);
+ return NULL;
+ }
+ return pFunc;
+}
+
+static SColumnNode* createColumnByFunc(const SFunctionNode* pFunc) {
+ SColumnNode* pCol = nodesMakeNode(QUERY_NODE_COLUMN);
+ if (NULL == pCol) {
+ return NULL;
+ }
+ strcpy(pCol->colName, pFunc->node.aliasName);
+ pCol->node.resType = pFunc->node.resType;
+ return pCol;
+}
+
+bool fmIsDistExecFunc(int32_t funcId) {
+ if (!fmIsVectorFunc(funcId)) {
+ return true;
+ }
+ return (NULL != funcMgtBuiltins[funcId].pPartialFunc && NULL != funcMgtBuiltins[funcId].pMergeFunc);
+}
+
+static int32_t createPartialFunction(const SFunctionNode* pSrcFunc, SFunctionNode** pPartialFunc) {
+ SNodeList* pParameterList = nodesCloneList(pSrcFunc->pParameterList);
+ if (NULL == pParameterList) {
+ return TSDB_CODE_OUT_OF_MEMORY;
+ }
+ *pPartialFunc = createFunction(funcMgtBuiltins[pSrcFunc->funcId].pPartialFunc, pParameterList);
+ if (NULL == *pPartialFunc) {
+ nodesDestroyList(pParameterList);
+ return TSDB_CODE_OUT_OF_MEMORY;
+ }
+ snprintf((*pPartialFunc)->node.aliasName, sizeof((*pPartialFunc)->node.aliasName), "%s.%p",
+ (*pPartialFunc)->functionName, pSrcFunc);
+ return TSDB_CODE_SUCCESS;
+}
+
+static int32_t createMergeFunction(const SFunctionNode* pSrcFunc, const SFunctionNode* pPartialFunc,
+ SFunctionNode** pMergeFunc) {
+ SNodeList* pParameterList = NULL;
+ nodesListMakeStrictAppend(&pParameterList, createColumnByFunc(pPartialFunc));
+ *pMergeFunc = createFunction(funcMgtBuiltins[pSrcFunc->funcId].pMergeFunc, pParameterList);
+ if (NULL == *pMergeFunc) {
+ nodesDestroyList(pParameterList);
+ return TSDB_CODE_OUT_OF_MEMORY;
+ }
+ strcpy((*pMergeFunc)->node.aliasName, pSrcFunc->node.aliasName);
+ return TSDB_CODE_SUCCESS;
+}
+
+int32_t fmGetDistMethod(const SFunctionNode* pFunc, SFunctionNode** pPartialFunc, SFunctionNode** pMergeFunc) {
+ if (!fmIsDistExecFunc(pFunc->funcId)) {
+ return TSDB_CODE_FAILED;
+ }
+
+ int32_t code = createPartialFunction(pFunc, pPartialFunc);
+ if (TSDB_CODE_SUCCESS == code) {
+ code = createMergeFunction(pFunc, *pPartialFunc, pMergeFunc);
+ }
+
+ if (TSDB_CODE_SUCCESS != code) {
+ nodesDestroyNode(*pPartialFunc);
+ nodesDestroyNode(*pMergeFunc);
+ }
+
+ return code;
+}
diff --git a/source/libs/index/inc/indexInt.h b/source/libs/index/inc/indexInt.h
index 81d43daf13..24a4e99970 100644
--- a/source/libs/index/inc/indexInt.h
+++ b/source/libs/index/inc/indexInt.h
@@ -131,8 +131,7 @@ typedef struct TFileCacheKey {
char* colName;
int32_t nColName;
} ICacheKey;
-
-int indexFlushCacheToTFile(SIndex* sIdx, void*);
+int indexFlushCacheToTFile(SIndex* sIdx, void*, bool quit);
int64_t indexAddRef(void* p);
int32_t indexRemoveRef(int64_t ref);
diff --git a/source/libs/index/src/index.c b/source/libs/index/src/index.c
index 3d905303d1..ba3aea969f 100644
--- a/source/libs/index/src/index.c
+++ b/source/libs/index/src/index.c
@@ -150,6 +150,7 @@ void indexClose(SIndex* sIdx) {
indexCacheForceToMerge((void*)(*pCache));
indexInfo("%s wait to merge", (*pCache)->colName);
indexWait((void*)(sIdx));
+ indexInfo("%s finish to wait", (*pCache)->colName);
iter = taosHashIterate(sIdx->colObj, iter);
indexCacheUnRef(*pCache);
}
@@ -454,7 +455,7 @@ static void indexDestroyFinalResult(SArray* result) {
taosArrayDestroy(result);
}
-int indexFlushCacheToTFile(SIndex* sIdx, void* cache) {
+int indexFlushCacheToTFile(SIndex* sIdx, void* cache, bool quit) {
if (sIdx == NULL) {
return -1;
}
@@ -464,7 +465,7 @@ int indexFlushCacheToTFile(SIndex* sIdx, void* cache) {
IndexCache* pCache = (IndexCache*)cache;
- while (sIdx->quit && atomic_load_32(&pCache->merging) == 1) {
+ while (quit && atomic_load_32(&pCache->merging) == 1) {
}
TFileReader* pReader = tfileGetReaderByCol(sIdx->tindex, pCache->suid, pCache->colName);
if (pReader == NULL) {
@@ -476,11 +477,11 @@ int indexFlushCacheToTFile(SIndex* sIdx, void* cache) {
indexError("%p immtable is empty, ignore merge opera", pCache);
indexCacheDestroyImm(pCache);
tfileReaderUnRef(pReader);
- if (sIdx->quit) {
+ atomic_store_32(&pCache->merging, 0);
+ if (quit) {
indexPost(sIdx);
}
indexReleaseRef(sIdx->refId);
- atomic_store_32(&pCache->merging, 0);
return 0;
}
@@ -539,10 +540,10 @@ int indexFlushCacheToTFile(SIndex* sIdx, void* cache) {
} else {
indexInfo("success to merge , time cost: %" PRId64 "ms", cost / 1000);
}
- if (sIdx->quit) {
+ atomic_store_32(&pCache->merging, 0);
+ if (quit) {
indexPost(sIdx);
}
- atomic_store_32(&pCache->merging, 0);
indexReleaseRef(sIdx->refId);
return ret;
diff --git a/source/libs/index/src/indexCache.c b/source/libs/index/src/indexCache.c
index 586a3ae573..4e7be245ef 100644
--- a/source/libs/index/src/indexCache.c
+++ b/source/libs/index/src/indexCache.c
@@ -728,9 +728,9 @@ static void doMergeWork(SSchedMsg* msg) {
IndexCache* pCache = msg->ahandle;
SIndex* sidx = (SIndex*)pCache->index;
- sidx->quit = msg->thandle ? true : false;
+ int quit = msg->thandle ? true : false;
taosMemoryFree(msg->thandle);
- indexFlushCacheToTFile(sidx, pCache);
+ indexFlushCacheToTFile(sidx, pCache, quit);
}
static bool indexCacheIteratorNext(Iterate* itera) {
SSkipListIterator* iter = itera->iter;
diff --git a/source/libs/index/test/jsonUT.cc b/source/libs/index/test/jsonUT.cc
index cd5a5d9b0f..48ce8839c4 100644
--- a/source/libs/index/test/jsonUT.cc
+++ b/source/libs/index/test/jsonUT.cc
@@ -51,6 +51,7 @@ class JsonEnv : public ::testing::Test {
tIndexJsonClose(index);
indexOptsDestroy(opts);
printf("destory\n");
+ taosMsleep(1000);
}
SIndexJsonOpts* opts;
SIndexJson* index;
diff --git a/source/libs/nodes/src/nodesCloneFuncs.c b/source/libs/nodes/src/nodesCloneFuncs.c
index cb4a4f104c..94661388cb 100644
--- a/source/libs/nodes/src/nodesCloneFuncs.c
+++ b/source/libs/nodes/src/nodesCloneFuncs.c
@@ -142,14 +142,16 @@ static SNode* valueNodeCopy(const SValueNode* pSrc, SValueNode* pDst) {
break;
case TSDB_DATA_TYPE_NCHAR:
case TSDB_DATA_TYPE_VARCHAR:
- case TSDB_DATA_TYPE_VARBINARY:
- pDst->datum.p = taosMemoryMalloc(pSrc->node.resType.bytes + VARSTR_HEADER_SIZE + 1);
+ case TSDB_DATA_TYPE_VARBINARY:{
+ int32_t len = varDataTLen(pSrc->datum.p) + 1;
+ pDst->datum.p = taosMemoryCalloc(1, len);
if (NULL == pDst->datum.p) {
nodesDestroyNode(pDst);
return NULL;
}
- memcpy(pDst->datum.p, pSrc->datum.p, pSrc->node.resType.bytes + VARSTR_HEADER_SIZE + 1);
+ memcpy(pDst->datum.p, pSrc->datum.p, len);
break;
+ }
case TSDB_DATA_TYPE_JSON:
case TSDB_DATA_TYPE_DECIMAL:
case TSDB_DATA_TYPE_BLOB:
@@ -371,7 +373,14 @@ static SNode* logicVnodeModifCopy(const SVnodeModifLogicNode* pSrc, SVnodeModifL
static SNode* logicExchangeCopy(const SExchangeLogicNode* pSrc, SExchangeLogicNode* pDst) {
COPY_BASE_OBJECT_FIELD(node, logicNodeCopy);
COPY_SCALAR_FIELD(srcGroupId);
- COPY_SCALAR_FIELD(precision);
+ return (SNode*)pDst;
+}
+
+static SNode* logicMergeCopy(const SMergeLogicNode* pSrc, SMergeLogicNode* pDst) {
+ COPY_BASE_OBJECT_FIELD(node, logicNodeCopy);
+ CLONE_NODE_LIST_FIELD(pMergeKeys);
+ COPY_SCALAR_FIELD(numOfChannels);
+ COPY_SCALAR_FIELD(srcGroupId);
return (SNode*)pDst;
}
@@ -535,6 +544,8 @@ SNodeptr nodesCloneNode(const SNodeptr pNode) {
return logicVnodeModifCopy((const SVnodeModifLogicNode*)pNode, (SVnodeModifLogicNode*)pDst);
case QUERY_NODE_LOGIC_PLAN_EXCHANGE:
return logicExchangeCopy((const SExchangeLogicNode*)pNode, (SExchangeLogicNode*)pDst);
+ case QUERY_NODE_LOGIC_PLAN_MERGE:
+ return logicMergeCopy((const SMergeLogicNode*)pNode, (SMergeLogicNode*)pDst);
case QUERY_NODE_LOGIC_PLAN_WINDOW:
return logicWindowCopy((const SWindowLogicNode*)pNode, (SWindowLogicNode*)pDst);
case QUERY_NODE_LOGIC_PLAN_FILL:
diff --git a/source/libs/nodes/src/nodesCodeFuncs.c b/source/libs/nodes/src/nodesCodeFuncs.c
index c0c8168eb1..4bce6381cd 100644
--- a/source/libs/nodes/src/nodesCodeFuncs.c
+++ b/source/libs/nodes/src/nodesCodeFuncs.c
@@ -190,6 +190,8 @@ const char* nodesNodeName(ENodeType type) {
return "LogicVnodeModif";
case QUERY_NODE_LOGIC_PLAN_EXCHANGE:
return "LogicExchange";
+ case QUERY_NODE_LOGIC_PLAN_MERGE:
+ return "LogicMerge";
case QUERY_NODE_LOGIC_PLAN_WINDOW:
return "LogicWindow";
case QUERY_NODE_LOGIC_PLAN_FILL:
@@ -220,6 +222,8 @@ const char* nodesNodeName(ENodeType type) {
return "PhysiAgg";
case QUERY_NODE_PHYSICAL_PLAN_EXCHANGE:
return "PhysiExchange";
+ case QUERY_NODE_PHYSICAL_PLAN_MERGE:
+ return "PhysiMerge";
case QUERY_NODE_PHYSICAL_PLAN_SORT:
return "PhysiSort";
case QUERY_NODE_PHYSICAL_PLAN_INTERVAL:
@@ -596,7 +600,6 @@ static int32_t jsonToLogicProjectNode(const SJson* pJson, void* pObj) {
}
static const char* jkExchangeLogicPlanSrcGroupId = "SrcGroupId";
-static const char* jkExchangeLogicPlanSrcPrecision = "Precision";
static int32_t logicExchangeNodeToJson(const void* pObj, SJson* pJson) {
const SExchangeLogicNode* pNode = (const SExchangeLogicNode*)pObj;
@@ -605,9 +608,6 @@ static int32_t logicExchangeNodeToJson(const void* pObj, SJson* pJson) {
if (TSDB_CODE_SUCCESS == code) {
code = tjsonAddIntegerToObject(pJson, jkExchangeLogicPlanSrcGroupId, pNode->srcGroupId);
}
- if (TSDB_CODE_SUCCESS == code) {
- code = tjsonAddIntegerToObject(pJson, jkExchangeLogicPlanSrcPrecision, pNode->precision);
- }
return code;
}
@@ -619,8 +619,144 @@ static int32_t jsonToLogicExchangeNode(const SJson* pJson, void* pObj) {
if (TSDB_CODE_SUCCESS == code) {
code = tjsonGetIntValue(pJson, jkExchangeLogicPlanSrcGroupId, &pNode->srcGroupId);
}
+
+ return code;
+}
+
+static const char* jkMergeLogicPlanMergeKeys = "MergeKeys";
+static const char* jkMergeLogicPlanNumOfChannels = "NumOfChannels";
+static const char* jkMergeLogicPlanSrcGroupId = "SrcGroupId";
+
+static int32_t logicMergeNodeToJson(const void* pObj, SJson* pJson) {
+ const SMergeLogicNode* pNode = (const SMergeLogicNode*)pObj;
+
+ int32_t code = logicPlanNodeToJson(pObj, pJson);
if (TSDB_CODE_SUCCESS == code) {
- code = tjsonGetUTinyIntValue(pJson, jkExchangeLogicPlanSrcPrecision, &pNode->precision);
+ code = nodeListToJson(pJson, jkMergeLogicPlanMergeKeys, pNode->pMergeKeys);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonAddIntegerToObject(pJson, jkMergeLogicPlanNumOfChannels, pNode->numOfChannels);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonAddIntegerToObject(pJson, jkMergeLogicPlanSrcGroupId, pNode->srcGroupId);
+ }
+
+ return code;
+}
+
+static int32_t jsonToLogicMergeNode(const SJson* pJson, void* pObj) {
+ SMergeLogicNode* pNode = (SMergeLogicNode*)pObj;
+
+ int32_t code = jsonToLogicPlanNode(pJson, pObj);
+ if (TSDB_CODE_SUCCESS == code) {
+ code = jsonToNodeList(pJson, jkMergeLogicPlanMergeKeys, &pNode->pMergeKeys);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonGetIntValue(pJson, jkMergeLogicPlanNumOfChannels, &pNode->numOfChannels);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonGetIntValue(pJson, jkMergeLogicPlanSrcGroupId, &pNode->srcGroupId);
+ }
+
+ return code;
+}
+
+static const char* jkWindowLogicPlanWinType = "WinType";
+static const char* jkWindowLogicPlanFuncs = "Funcs";
+static const char* jkWindowLogicPlanInterval = "Interval";
+static const char* jkWindowLogicPlanOffset = "Offset";
+static const char* jkWindowLogicPlanSliding = "Sliding";
+static const char* jkWindowLogicPlanIntervalUnit = "IntervalUnit";
+static const char* jkWindowLogicPlanSlidingUnit = "SlidingUnit";
+static const char* jkWindowLogicPlanSessionGap = "SessionGap";
+static const char* jkWindowLogicPlanTspk = "Tspk";
+static const char* jkWindowLogicPlanStateExpr = "StateExpr";
+static const char* jkWindowLogicPlanTriggerType = "TriggerType";
+static const char* jkWindowLogicPlanWatermark = "Watermark";
+
+static int32_t logicWindowNodeToJson(const void* pObj, SJson* pJson) {
+ const SWindowLogicNode* pNode = (const SWindowLogicNode*)pObj;
+
+ int32_t code = logicPlanNodeToJson(pObj, pJson);
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonAddIntegerToObject(pJson, jkWindowLogicPlanWinType, pNode->winType);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = nodeListToJson(pJson, jkWindowLogicPlanFuncs, pNode->pFuncs);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonAddIntegerToObject(pJson, jkWindowLogicPlanInterval, pNode->interval);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonAddIntegerToObject(pJson, jkWindowLogicPlanOffset, pNode->offset);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonAddIntegerToObject(pJson, jkWindowLogicPlanSliding, pNode->sliding);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonAddIntegerToObject(pJson, jkWindowLogicPlanIntervalUnit, pNode->intervalUnit);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonAddIntegerToObject(pJson, jkWindowLogicPlanSlidingUnit, pNode->slidingUnit);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonAddIntegerToObject(pJson, jkWindowLogicPlanSessionGap, pNode->sessionGap);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonAddObject(pJson, jkWindowLogicPlanTspk, nodeToJson, pNode->pTspk);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonAddObject(pJson, jkWindowLogicPlanStateExpr, nodeToJson, pNode->pStateExpr);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonAddIntegerToObject(pJson, jkWindowLogicPlanTriggerType, pNode->triggerType);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonAddIntegerToObject(pJson, jkWindowLogicPlanWatermark, pNode->watermark);
+ }
+
+ return code;
+}
+
+static int32_t jsonToLogicWindowNode(const SJson* pJson, void* pObj) {
+ SWindowLogicNode* pNode = (SWindowLogicNode*)pObj;
+
+ int32_t code = jsonToLogicPlanNode(pJson, pObj);
+ if (TSDB_CODE_SUCCESS == code) {
+ tjsonGetNumberValue(pJson, jkWindowLogicPlanWinType, pNode->winType, code);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = jsonToNodeList(pJson, jkWindowLogicPlanFuncs, &pNode->pFuncs);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonGetBigIntValue(pJson, jkWindowLogicPlanInterval, &pNode->interval);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonGetBigIntValue(pJson, jkWindowLogicPlanOffset, &pNode->offset);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonGetBigIntValue(pJson, jkWindowLogicPlanSliding, &pNode->sliding);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonGetTinyIntValue(pJson, jkWindowLogicPlanIntervalUnit, &pNode->intervalUnit);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonGetTinyIntValue(pJson, jkWindowLogicPlanSlidingUnit, &pNode->slidingUnit);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonGetBigIntValue(pJson, jkWindowLogicPlanSessionGap, &pNode->sessionGap);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = jsonToNodeObject(pJson, jkWindowLogicPlanTspk, &pNode->pTspk);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = jsonToNodeObject(pJson, jkWindowLogicPlanStateExpr, &pNode->pStateExpr);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonGetTinyIntValue(pJson, jkWindowLogicPlanTriggerType, &pNode->triggerType);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonGetBigIntValue(pJson, jkWindowLogicPlanWatermark, &pNode->watermark);
}
return code;
@@ -1459,6 +1595,44 @@ static int32_t jsonToPhysiExchangeNode(const SJson* pJson, void* pObj) {
return code;
}
+static const char* jkMergePhysiPlanMergeKeys = "MergeKeys";
+static const char* jkMergePhysiPlanNumOfChannels = "NumOfChannels";
+static const char* jkMergePhysiPlanSrcGroupId = "SrcGroupId";
+
+static int32_t physiMergeNodeToJson(const void* pObj, SJson* pJson) {
+ const SMergePhysiNode* pNode = (const SMergePhysiNode*)pObj;
+
+ int32_t code = physicPlanNodeToJson(pObj, pJson);
+ if (TSDB_CODE_SUCCESS == code) {
+ code = nodeListToJson(pJson, jkMergePhysiPlanMergeKeys, pNode->pMergeKeys);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonAddIntegerToObject(pJson, jkMergePhysiPlanNumOfChannels, pNode->numOfChannels);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonAddIntegerToObject(pJson, jkMergePhysiPlanSrcGroupId, pNode->srcGroupId);
+ }
+
+ return code;
+}
+
+static int32_t jsonToPhysiMergeNode(const SJson* pJson, void* pObj) {
+ SMergePhysiNode* pNode = (SMergePhysiNode*)pObj;
+
+ int32_t code = jsonToPhysicPlanNode(pJson, pObj);
+ if (TSDB_CODE_SUCCESS == code) {
+ code = jsonToNodeList(pJson, jkMergePhysiPlanMergeKeys, &pNode->pMergeKeys);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonGetIntValue(pJson, jkMergePhysiPlanNumOfChannels, &pNode->numOfChannels);
+ }
+ if (TSDB_CODE_SUCCESS == code) {
+ code = tjsonGetIntValue(pJson, jkMergePhysiPlanSrcGroupId, &pNode->srcGroupId);
+ }
+
+ return code;
+}
+
static const char* jkSortPhysiPlanExprs = "Exprs";
static const char* jkSortPhysiPlanSortKeys = "SortKeys";
static const char* jkSortPhysiPlanTargets = "Targets";
@@ -3401,6 +3575,10 @@ static int32_t specificNodeToJson(const void* pObj, SJson* pJson) {
break;
case QUERY_NODE_LOGIC_PLAN_EXCHANGE:
return logicExchangeNodeToJson(pObj, pJson);
+ case QUERY_NODE_LOGIC_PLAN_MERGE:
+ return logicMergeNodeToJson(pObj, pJson);
+ case QUERY_NODE_LOGIC_PLAN_WINDOW:
+ return logicWindowNodeToJson(pObj, pJson);
case QUERY_NODE_LOGIC_PLAN_FILL:
return logicFillNodeToJson(pObj, pJson);
case QUERY_NODE_LOGIC_PLAN_SORT:
@@ -3427,6 +3605,8 @@ static int32_t specificNodeToJson(const void* pObj, SJson* pJson) {
return physiAggNodeToJson(pObj, pJson);
case QUERY_NODE_PHYSICAL_PLAN_EXCHANGE:
return physiExchangeNodeToJson(pObj, pJson);
+ case QUERY_NODE_PHYSICAL_PLAN_MERGE:
+ return physiMergeNodeToJson(pObj, pJson);
case QUERY_NODE_PHYSICAL_PLAN_SORT:
return physiSortNodeToJson(pObj, pJson);
case QUERY_NODE_PHYSICAL_PLAN_INTERVAL:
@@ -3512,6 +3692,10 @@ static int32_t jsonToSpecificNode(const SJson* pJson, void* pObj) {
return jsonToLogicProjectNode(pJson, pObj);
case QUERY_NODE_LOGIC_PLAN_EXCHANGE:
return jsonToLogicExchangeNode(pJson, pObj);
+ case QUERY_NODE_LOGIC_PLAN_MERGE:
+ return jsonToLogicMergeNode(pJson, pObj);
+ case QUERY_NODE_LOGIC_PLAN_WINDOW:
+ return jsonToLogicWindowNode(pJson, pObj);
case QUERY_NODE_LOGIC_PLAN_FILL:
return jsonToLogicFillNode(pJson, pObj);
case QUERY_NODE_LOGIC_PLAN_SORT:
@@ -3538,6 +3722,8 @@ static int32_t jsonToSpecificNode(const SJson* pJson, void* pObj) {
return jsonToPhysiAggNode(pJson, pObj);
case QUERY_NODE_PHYSICAL_PLAN_EXCHANGE:
return jsonToPhysiExchangeNode(pJson, pObj);
+ case QUERY_NODE_PHYSICAL_PLAN_MERGE:
+ return jsonToPhysiMergeNode(pJson, pObj);
case QUERY_NODE_PHYSICAL_PLAN_SORT:
return jsonToPhysiSortNode(pJson, pObj);
case QUERY_NODE_PHYSICAL_PLAN_INTERVAL:
diff --git a/source/libs/nodes/src/nodesUtilFuncs.c b/source/libs/nodes/src/nodesUtilFuncs.c
index d29e89d266..51111ad864 100644
--- a/source/libs/nodes/src/nodesUtilFuncs.c
+++ b/source/libs/nodes/src/nodesUtilFuncs.c
@@ -220,6 +220,8 @@ SNodeptr nodesMakeNode(ENodeType type) {
return makeNode(type, sizeof(SVnodeModifLogicNode));
case QUERY_NODE_LOGIC_PLAN_EXCHANGE:
return makeNode(type, sizeof(SExchangeLogicNode));
+ case QUERY_NODE_LOGIC_PLAN_MERGE:
+ return makeNode(type, sizeof(SMergeLogicNode));
case QUERY_NODE_LOGIC_PLAN_WINDOW:
return makeNode(type, sizeof(SWindowLogicNode));
case QUERY_NODE_LOGIC_PLAN_FILL:
@@ -250,6 +252,8 @@ SNodeptr nodesMakeNode(ENodeType type) {
return makeNode(type, sizeof(SAggPhysiNode));
case QUERY_NODE_PHYSICAL_PLAN_EXCHANGE:
return makeNode(type, sizeof(SExchangePhysiNode));
+ case QUERY_NODE_PHYSICAL_PLAN_MERGE:
+ return makeNode(type, sizeof(SMergePhysiNode));
case QUERY_NODE_PHYSICAL_PLAN_SORT:
return makeNode(type, sizeof(SSortPhysiNode));
case QUERY_NODE_PHYSICAL_PLAN_INTERVAL:
diff --git a/source/libs/parser/inc/parUtil.h b/source/libs/parser/inc/parUtil.h
index 2468f7d75b..0351023f5b 100644
--- a/source/libs/parser/inc/parUtil.h
+++ b/source/libs/parser/inc/parUtil.h
@@ -58,7 +58,7 @@ int32_t getNumOfColumns(const STableMeta* pTableMeta);
int32_t getNumOfTags(const STableMeta* pTableMeta);
STableComInfo getTableInfo(const STableMeta* pTableMeta);
STableMeta* tableMetaDup(const STableMeta* pTableMeta);
-int32_t parseJsontoTagData(const char* json, SKVRowBuilder* kvRowBuilder, SMsgBuf* errMsg, int16_t startColId);
+int32_t parseJsontoTagData(const char* json, SArray* pTagVals, STag **ppTag, SMsgBuf* pMsgBuf);
int32_t trimString(const char* src, int32_t len, char* dst, int32_t dlen);
diff --git a/source/libs/parser/src/parInsert.c b/source/libs/parser/src/parInsert.c
index f5a079318c..593a597a82 100644
--- a/source/libs/parser/src/parInsert.c
+++ b/source/libs/parser/src/parInsert.c
@@ -54,7 +54,6 @@ typedef struct SInsertParseContext {
SMsgBuf msg; // input
STableMeta* pTableMeta; // each table
SParsedDataColInfo tags; // each table
- SKVRowBuilder tagsBuilder; // each table
SVCreateTbReq createTblReq; // each table
SHashObj* pVgroupsHashObj; // global
SHashObj* pTableBlockHashObj; // global
@@ -74,9 +73,10 @@ static uint8_t TRUE_VALUE = (uint8_t)TSDB_TRUE;
static uint8_t FALSE_VALUE = (uint8_t)TSDB_FALSE;
typedef struct SKvParam {
- SKVRowBuilder* builder;
- SSchema* schema;
- char buf[TSDB_MAX_TAGS_LEN];
+ int16_t pos;
+ SArray* pTagVals;
+ SSchema* schema;
+ char buf[TSDB_MAX_TAGS_LEN];
} SKvParam;
typedef struct SMemParam {
@@ -447,7 +447,7 @@ static int parseTime(char** end, SToken* pToken, int16_t timePrec, int64_t* time
return TSDB_CODE_SUCCESS;
}
-static FORCE_INLINE int32_t checkAndTrimValue(SToken* pToken, uint32_t type, char* tmpTokenBuf, SMsgBuf* pMsgBuf) {
+static FORCE_INLINE int32_t checkAndTrimValue(SToken* pToken, char* tmpTokenBuf, SMsgBuf* pMsgBuf) {
if ((pToken->type != TK_NOW && pToken->type != TK_TODAY && pToken->type != TK_NK_INTEGER &&
pToken->type != TK_NK_STRING && pToken->type != TK_NK_FLOAT && pToken->type != TK_NK_BOOL &&
pToken->type != TK_NULL && pToken->type != TK_NK_HEX && pToken->type != TK_NK_OCT &&
@@ -493,7 +493,7 @@ static int32_t parseValueToken(char** end, SToken* pToken, SSchema* pSchema, int
uint64_t uv;
char* endptr = NULL;
- int32_t code = checkAndTrimValue(pToken, pSchema->type, tmpTokenBuf, pMsgBuf);
+ int32_t code = checkAndTrimValue(pToken, tmpTokenBuf, pMsgBuf);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
@@ -642,14 +642,12 @@ static int32_t parseValueToken(char** end, SToken* pToken, SSchema* pSchema, int
case TSDB_DATA_TYPE_NCHAR: {
return func(pMsgBuf, pToken->z, pToken->n, param);
}
-
case TSDB_DATA_TYPE_JSON: {
if (pToken->n > (TSDB_MAX_JSON_TAG_LEN - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE) {
return buildSyntaxErrMsg(pMsgBuf, "json string too long than 4095", pToken->z);
}
return func(pMsgBuf, pToken->z, pToken->n, param);
}
-
case TSDB_DATA_TYPE_TIMESTAMP: {
int64_t tmpVal;
if (parseTime(end, pToken, timePrec, &tmpVal, pMsgBuf) != TSDB_CODE_SUCCESS) {
@@ -774,99 +772,282 @@ static int32_t parseBoundColumns(SInsertParseContext* pCxt, SParsedDataColInfo*
return TSDB_CODE_SUCCESS;
}
-static int32_t KvRowAppend(SMsgBuf* pMsgBuf, const void* value, int32_t len, void* param) {
- SKvParam* pa = (SKvParam*)param;
-
- int8_t type = pa->schema->type;
- int16_t colId = pa->schema->colId;
-
- if (TSDB_DATA_TYPE_JSON == type) {
- return parseJsontoTagData(value, pa->builder, pMsgBuf, colId);
- }
-
- if (value == NULL) { // it is a null data
- // tdAppendColValToRow(rb, pa->schema->colId, pa->schema->type, TD_VTYPE_NULL, value, false, pa->toffset,
- // pa->colIdx);
- return TSDB_CODE_SUCCESS;
- }
-
- if (TSDB_DATA_TYPE_BINARY == type) {
- STR_WITH_SIZE_TO_VARSTR(pa->buf, value, len);
- tdAddColToKVRow(pa->builder, colId, pa->buf, varDataTLen(pa->buf));
- } else if (TSDB_DATA_TYPE_NCHAR == type) {
- // if the converted output len is over than pColumnModel->bytes, return error: 'Argument list too long'
- int32_t output = 0;
- if (!taosMbsToUcs4(value, len, (TdUcs4*)varDataVal(pa->buf), pa->schema->bytes - VARSTR_HEADER_SIZE, &output)) {
- if (errno == E2BIG) {
- return generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pa->schema->name);
- }
-
- char buf[512] = {0};
- snprintf(buf, tListLen(buf), " taosMbsToUcs4 error:%s", strerror(errno));
- return buildSyntaxErrMsg(pMsgBuf, buf, value);
- }
-
- varDataSetLen(pa->buf, output);
- tdAddColToKVRow(pa->builder, colId, pa->buf, varDataTLen(pa->buf));
- } else {
- tdAddColToKVRow(pa->builder, colId, value, TYPE_BYTES[type]);
- }
-
- return TSDB_CODE_SUCCESS;
-}
-
-static int32_t buildCreateTbReq(SVCreateTbReq* pTbReq, const char* tname, SKVRow row, int64_t suid) {
+static void buildCreateTbReq(SVCreateTbReq* pTbReq, const char* tname, STag* pTag, int64_t suid) {
pTbReq->type = TD_CHILD_TABLE;
pTbReq->name = strdup(tname);
pTbReq->ctb.suid = suid;
- pTbReq->ctb.pTag = row;
+ pTbReq->ctb.pTag = (uint8_t*)pTag;
+
+ return;
+}
+
+static int32_t parseTagToken(char** end, SToken* pToken, SSchema* pSchema, int16_t timePrec, STagVal* val,
+ SMsgBuf* pMsgBuf) {
+ int64_t iv;
+ uint64_t uv;
+ char* endptr = NULL;
+
+ if (isNullStr(pToken)) {
+ if (TSDB_DATA_TYPE_TIMESTAMP == pSchema->type && PRIMARYKEY_TIMESTAMP_COL_ID == pSchema->colId) {
+ return buildSyntaxErrMsg(pMsgBuf, "primary timestamp should not be null", pToken->z);
+ }
+
+ return TSDB_CODE_SUCCESS;
+ }
+
+ val->cid = pSchema->colId;
+ val->type = pSchema->type;
+
+ switch (pSchema->type) {
+ case TSDB_DATA_TYPE_BOOL: {
+ if ((pToken->type == TK_NK_BOOL || pToken->type == TK_NK_STRING) && (pToken->n != 0)) {
+ if (strncmp(pToken->z, "true", pToken->n) == 0) {
+ *(int8_t*)(&val->i64) = TRUE_VALUE;
+ } else if (strncmp(pToken->z, "false", pToken->n) == 0) {
+ *(int8_t*)(&val->i64) = FALSE_VALUE;
+ } else {
+ return buildSyntaxErrMsg(pMsgBuf, "invalid bool data", pToken->z);
+ }
+ } else if (pToken->type == TK_NK_INTEGER) {
+ *(int8_t*)(&val->i64) = ((taosStr2Int64(pToken->z, NULL, 10) == 0) ? FALSE_VALUE : TRUE_VALUE);
+ } else if (pToken->type == TK_NK_FLOAT) {
+ *(int8_t*)(&val->i64) = ((taosStr2Double(pToken->z, NULL) == 0) ? FALSE_VALUE : TRUE_VALUE);
+ } else {
+ return buildSyntaxErrMsg(pMsgBuf, "invalid bool data", pToken->z);
+ }
+ break;
+ }
+
+ case TSDB_DATA_TYPE_TINYINT: {
+ if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &iv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "invalid tinyint data", pToken->z);
+ } else if (!IS_VALID_TINYINT(iv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "tinyint data overflow", pToken->z);
+ }
+
+ *(int8_t*)(&val->i64) = iv;
+ break;
+ }
+
+ case TSDB_DATA_TYPE_UTINYINT: {
+ if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &uv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "invalid unsigned tinyint data", pToken->z);
+ } else if (!IS_VALID_UTINYINT(uv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "unsigned tinyint data overflow", pToken->z);
+ }
+ *(uint8_t*)(&val->i64) = uv;
+ break;
+ }
+
+ case TSDB_DATA_TYPE_SMALLINT: {
+ if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &iv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "invalid smallint data", pToken->z);
+ } else if (!IS_VALID_SMALLINT(iv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "smallint data overflow", pToken->z);
+ }
+ *(int16_t*)(&val->i64) = iv;
+ break;
+ }
+
+ case TSDB_DATA_TYPE_USMALLINT: {
+ if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &uv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "invalid unsigned smallint data", pToken->z);
+ } else if (!IS_VALID_USMALLINT(uv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "unsigned smallint data overflow", pToken->z);
+ }
+ *(uint16_t*)(&val->i64) = uv;
+ break;
+ }
+
+ case TSDB_DATA_TYPE_INT: {
+ if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &iv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "invalid int data", pToken->z);
+ } else if (!IS_VALID_INT(iv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "int data overflow", pToken->z);
+ }
+ *(int32_t*)(&val->i64) = iv;
+ break;
+ }
+
+ case TSDB_DATA_TYPE_UINT: {
+ if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &uv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "invalid unsigned int data", pToken->z);
+ } else if (!IS_VALID_UINT(uv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "unsigned int data overflow", pToken->z);
+ }
+ *(uint32_t*)(&val->i64) = uv;
+ break;
+ }
+
+ case TSDB_DATA_TYPE_BIGINT: {
+ if (TSDB_CODE_SUCCESS != toInteger(pToken->z, pToken->n, 10, &iv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "invalid bigint data", pToken->z);
+ } else if (!IS_VALID_BIGINT(iv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "bigint data overflow", pToken->z);
+ }
+
+ val->i64 = iv;
+ break;
+ }
+
+ case TSDB_DATA_TYPE_UBIGINT: {
+ if (TSDB_CODE_SUCCESS != toUInteger(pToken->z, pToken->n, 10, &uv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "invalid unsigned bigint data", pToken->z);
+ } else if (!IS_VALID_UBIGINT(uv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "unsigned bigint data overflow", pToken->z);
+ }
+ *(uint64_t*)(&val->i64) = uv;
+ break;
+ }
+
+ case TSDB_DATA_TYPE_FLOAT: {
+ double dv;
+ if (TK_NK_ILLEGAL == toDouble(pToken, &dv, &endptr)) {
+ return buildSyntaxErrMsg(pMsgBuf, "illegal float data", pToken->z);
+ }
+ if (((dv == HUGE_VAL || dv == -HUGE_VAL) && errno == ERANGE) || dv > FLT_MAX || dv < -FLT_MAX || isinf(dv) ||
+ isnan(dv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "illegal float data", pToken->z);
+ }
+ *(float*)(&val->i64) = dv;
+ break;
+ }
+
+ case TSDB_DATA_TYPE_DOUBLE: {
+ double dv;
+ if (TK_NK_ILLEGAL == toDouble(pToken, &dv, &endptr)) {
+ return buildSyntaxErrMsg(pMsgBuf, "illegal double data", pToken->z);
+ }
+ if (((dv == HUGE_VAL || dv == -HUGE_VAL) && errno == ERANGE) || isinf(dv) || isnan(dv)) {
+ return buildSyntaxErrMsg(pMsgBuf, "illegal double data", pToken->z);
+ }
+
+ *(double*)(&val->i64) = dv;
+ break;
+ }
+
+ case TSDB_DATA_TYPE_BINARY: {
+ // Too long values will raise the invalid sql error message
+ if (pToken->n + VARSTR_HEADER_SIZE > pSchema->bytes) {
+ return generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
+ }
+ val->pData = pToken->z;
+ val->nData = pToken->n;
+ break;
+ }
+
+ case TSDB_DATA_TYPE_NCHAR: {
+ int32_t output = 0;
+ void* p = taosMemoryCalloc(1, pToken->n * TSDB_NCHAR_SIZE);
+ if (p == NULL) {
+ return TSDB_CODE_OUT_OF_MEMORY;
+ }
+ if (!taosMbsToUcs4(pToken->z, pToken->n, (TdUcs4*)(p), pToken->n * TSDB_NCHAR_SIZE, &output)) {
+ if (errno == E2BIG) {
+ taosMemoryFree(p);
+ return generateSyntaxErrMsg(pMsgBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pSchema->name);
+ }
+ char buf[512] = {0};
+ snprintf(buf, tListLen(buf), " taosMbsToUcs4 error:%s", strerror(errno));
+ taosMemoryFree(p);
+ return buildSyntaxErrMsg(pMsgBuf, buf, pToken->z);
+ }
+ val->pData = p;
+ val->nData = output;
+ break;
+ }
+ case TSDB_DATA_TYPE_TIMESTAMP: {
+ if (parseTime(end, pToken, timePrec, &iv, pMsgBuf) != TSDB_CODE_SUCCESS) {
+ return buildSyntaxErrMsg(pMsgBuf, "invalid timestamp", pToken->z);
+ }
+
+ val->i64 = iv;
+ break;
+ }
+ }
return TSDB_CODE_SUCCESS;
}
// pSql -> tag1_value, ...)
static int32_t parseTagsClause(SInsertParseContext* pCxt, SSchema* pSchema, uint8_t precision, const char* tName) {
- if (tdInitKVRowBuilder(&pCxt->tagsBuilder) < 0) {
- return TSDB_CODE_TSC_OUT_OF_MEMORY;
- }
-
- SKvParam param = {.builder = &pCxt->tagsBuilder};
- SToken sToken;
- bool isParseBindParam = false;
- char tmpTokenBuf[TSDB_MAX_BYTES_PER_ROW] = {0}; // used for deleting Escape character: \\, \', \"
+ int32_t code = TSDB_CODE_SUCCESS;
+ SArray* pTagVals = taosArrayInit(pCxt->tags.numOfBound, sizeof(STagVal));
+ SToken sToken;
+ bool isParseBindParam = false;
+ bool isJson = false;
+ STag* pTag = NULL;
for (int i = 0; i < pCxt->tags.numOfBound; ++i) {
NEXT_TOKEN_WITH_PREV(pCxt->pSql, sToken);
if (sToken.type == TK_NK_QUESTION) {
isParseBindParam = true;
if (NULL == pCxt->pStmtCb) {
- return buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", sToken.z);
+ code = buildSyntaxErrMsg(&pCxt->msg, "? only used in stmt", sToken.z);
+ goto end;
}
continue;
}
if (isParseBindParam) {
- return buildInvalidOperationMsg(&pCxt->msg, "no mix usage for ? and tag values");
+ code = buildInvalidOperationMsg(&pCxt->msg, "no mix usage for ? and tag values");
+ goto end;
}
SSchema* pTagSchema = &pSchema[pCxt->tags.boundColumns[i]];
- param.schema = pTagSchema;
- CHECK_CODE(
- parseValueToken(&pCxt->pSql, &sToken, pTagSchema, precision, tmpTokenBuf, KvRowAppend, ¶m, &pCxt->msg));
+ char* tmpTokenBuf = taosMemoryCalloc(1, sToken.n); // this can be optimize with parse column
+ code = checkAndTrimValue(&sToken, tmpTokenBuf, &pCxt->msg);
+ if (code != TSDB_CODE_SUCCESS) {
+ taosMemoryFree(tmpTokenBuf);
+ goto end;
+ }
+ if (pTagSchema->type == TSDB_DATA_TYPE_JSON) {
+ if (sToken.n > (TSDB_MAX_JSON_TAG_LEN - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE) {
+ code = buildSyntaxErrMsg(&pCxt->msg, "json string too long than 4095", sToken.z);
+ taosMemoryFree(tmpTokenBuf);
+ goto end;
+ }
+ code = parseJsontoTagData(sToken.z, pTagVals, &pTag, &pCxt->msg);
+ taosMemoryFree(tmpTokenBuf);
+ if (code != TSDB_CODE_SUCCESS) {
+ goto end;
+ }
+ isJson = true;
+ } else {
+ STagVal val = {0};
+ code = parseTagToken(&pCxt->pSql, &sToken, pTagSchema, precision, &val, &pCxt->msg);
+ if (TSDB_CODE_SUCCESS != code) {
+ taosMemoryFree(tmpTokenBuf);
+ goto end;
+ }
+ if (pTagSchema->type != TSDB_DATA_TYPE_BINARY) {
+ taosMemoryFree(tmpTokenBuf);
+ }
+ taosArrayPush(pTagVals, &val);
+ }
}
if (isParseBindParam) {
- return TSDB_CODE_SUCCESS;
+ code = TSDB_CODE_SUCCESS;
+ goto end;
}
- SKVRow row = tdGetKVRowFromBuilder(&pCxt->tagsBuilder);
- if (NULL == row) {
- return buildInvalidOperationMsg(&pCxt->msg, "out of memory");
+ if (!isJson && (code = tTagNew(pTagVals, 1, false, &pTag)) != TSDB_CODE_SUCCESS) {
+ goto end;
}
- tdSortKVRowByColIdx(row);
- return buildCreateTbReq(&pCxt->createTblReq, tName, row, pCxt->pTableMeta->suid);
+ buildCreateTbReq(&pCxt->createTblReq, tName, pTag, pCxt->pTableMeta->suid);
+
+end:
+ for (int i = 0; i < taosArrayGetSize(pTagVals); ++i) {
+ STagVal* p = (STagVal*)taosArrayGet(pTagVals, i);
+ if (IS_VAR_DATA_TYPE(p->type)) {
+ taosMemoryFree(p->pData);
+ }
+ }
+ taosArrayDestroy(pTagVals);
+ return code;
}
static int32_t cloneTableMeta(STableMeta* pSrc, STableMeta** pDst) {
@@ -1087,7 +1268,6 @@ void destroyCreateSubTbReq(SVCreateTbReq* pReq) {
static void destroyInsertParseContextForTable(SInsertParseContext* pCxt) {
taosMemoryFreeClear(pCxt->pTableMeta);
destroyBoundColumnInfo(&pCxt->tags);
- tdDestroyKVRowBuilder(&pCxt->tagsBuilder);
destroyCreateSubTbReq(&pCxt->createTblReq);
}
@@ -1537,46 +1717,93 @@ int32_t qBindStmtTagsValue(void* pBlock, void* boundTags, int64_t suid, char* tN
return TSDB_CODE_QRY_APP_ERROR;
}
- SKVRowBuilder tagBuilder;
- if (tdInitKVRowBuilder(&tagBuilder) < 0) {
- return TSDB_CODE_TSC_OUT_OF_MEMORY;
+ SArray* pTagArray = taosArrayInit(tags->numOfBound, sizeof(STagVal));
+ if (!pTagArray) {
+ return buildInvalidOperationMsg(&pBuf, "out of memory");
}
+ int32_t code = TSDB_CODE_SUCCESS;
SSchema* pSchema = pDataBlock->pTableMeta->schema;
- SKvParam param = {.builder = &tagBuilder};
+
+ bool isJson = false;
+ STag* pTag = NULL;
for (int c = 0; c < tags->numOfBound; ++c) {
- SSchema* pTagSchema = &pSchema[tags->boundColumns[c]];
- param.schema = pTagSchema;
-
if (bind[c].is_null && bind[c].is_null[0]) {
- KvRowAppend(&pBuf, NULL, 0, ¶m);
continue;
}
- int32_t colLen = pTagSchema->bytes;
+ SSchema* pTagSchema = &pSchema[tags->boundColumns[c]];
+ int32_t colLen = pTagSchema->bytes;
if (IS_VAR_DATA_TYPE(pTagSchema->type)) {
colLen = bind[c].length[0];
}
+ if (pTagSchema->type == TSDB_DATA_TYPE_JSON) {
+ if (colLen > (TSDB_MAX_JSON_TAG_LEN - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE) {
+ code = buildSyntaxErrMsg(&pBuf, "json string too long than 4095", bind[c].buffer);
+ goto end;
+ }
- CHECK_CODE(KvRowAppend(&pBuf, (char*)bind[c].buffer, colLen, ¶m));
+ isJson = true;
+ char* tmp = taosMemoryCalloc(1, colLen + 1);
+ memcpy(tmp, bind[c].buffer, colLen);
+ code = parseJsontoTagData(tmp, pTagArray, &pTag, &pBuf);
+ taosMemoryFree(tmp);
+ if (code != TSDB_CODE_SUCCESS) {
+ goto end;
+ }
+ } else {
+ STagVal val = {.cid = pTagSchema->colId, .type = pTagSchema->type};
+ if (pTagSchema->type == TSDB_DATA_TYPE_BINARY) {
+ val.pData = (uint8_t*)bind[c].buffer;
+ val.nData = colLen;
+ } else if (pTagSchema->type == TSDB_DATA_TYPE_NCHAR) {
+ int32_t output = 0;
+ void* p = taosMemoryCalloc(1, colLen * TSDB_NCHAR_SIZE);
+ if (p == NULL) {
+ code = TSDB_CODE_OUT_OF_MEMORY;
+ goto end;
+ }
+ if (!taosMbsToUcs4(bind[c].buffer, colLen, (TdUcs4*)(p), colLen * TSDB_NCHAR_SIZE, &output)) {
+ if (errno == E2BIG) {
+ taosMemoryFree(p);
+ code = generateSyntaxErrMsg(&pBuf, TSDB_CODE_PAR_VALUE_TOO_LONG, pTagSchema->name);
+ goto end;
+ }
+ char buf[512] = {0};
+ snprintf(buf, tListLen(buf), " taosMbsToUcs4 error:%s", strerror(errno));
+ taosMemoryFree(p);
+ code = buildSyntaxErrMsg(&pBuf, buf, bind[c].buffer);
+ goto end;
+ }
+ val.pData = p;
+ val.nData = output;
+ } else {
+ memcpy(&val.i64, bind[c].buffer, colLen);
+ }
+ taosArrayPush(pTagArray, &val);
+ }
}
- SKVRow row = tdGetKVRowFromBuilder(&tagBuilder);
- if (NULL == row) {
- tdDestroyKVRowBuilder(&tagBuilder);
- return buildInvalidOperationMsg(&pBuf, "out of memory");
+ if (!isJson && (code = tTagNew(pTagArray, 1, false, &pTag)) != TSDB_CODE_SUCCESS) {
+ goto end;
}
- tdSortKVRowByColIdx(row);
SVCreateTbReq tbReq = {0};
- CHECK_CODE(buildCreateTbReq(&tbReq, tName, row, suid));
- CHECK_CODE(buildCreateTbMsg(pDataBlock, &tbReq));
-
+ buildCreateTbReq(&tbReq, tName, pTag, suid);
+ code = buildCreateTbMsg(pDataBlock, &tbReq);
destroyCreateSubTbReq(&tbReq);
- tdDestroyKVRowBuilder(&tagBuilder);
- return TSDB_CODE_SUCCESS;
+end:
+ for (int i = 0; i < taosArrayGetSize(pTagArray); ++i) {
+ STagVal* p = (STagVal*)taosArrayGet(pTagArray, i);
+ if (p->type == TSDB_DATA_TYPE_NCHAR) {
+ taosMemoryFree(p->pData);
+ }
+ }
+ taosArrayDestroy(pTagArray);
+
+ return code;
}
int32_t qBindStmtColsValue(void* pBlock, TAOS_MULTI_BIND* bind, char* msgBuf, int32_t msgBufLen) {
@@ -1745,7 +1972,8 @@ int32_t qBindStmtSingleColValue(void* pBlock, TAOS_MULTI_BIND* bind, char* msgBu
return TSDB_CODE_SUCCESS;
}
-int32_t buildBoundFields(SParsedDataColInfo* boundInfo, SSchema* pSchema, int32_t* fieldNum, TAOS_FIELD_E** fields, uint8_t timePrec) {
+int32_t buildBoundFields(SParsedDataColInfo* boundInfo, SSchema* pSchema, int32_t* fieldNum, TAOS_FIELD_E** fields,
+ uint8_t timePrec) {
if (fields) {
*fields = taosMemoryCalloc(boundInfo->numOfBound, sizeof(TAOS_FIELD));
if (NULL == *fields) {
@@ -1756,7 +1984,7 @@ int32_t buildBoundFields(SParsedDataColInfo* boundInfo, SSchema* pSchema, int32_
if (TSDB_DATA_TYPE_TIMESTAMP == schema->type) {
(*fields)[0].precision = timePrec;
}
-
+
for (int32_t i = 0; i < boundInfo->numOfBound; ++i) {
schema = &pSchema[boundInfo->boundColumns[i]];
strcpy((*fields)[i].name, schema->name);
@@ -1802,7 +2030,8 @@ int32_t qBuildStmtColFields(void* pBlock, int32_t* fieldNum, TAOS_FIELD_E** fiel
return TSDB_CODE_SUCCESS;
}
- CHECK_CODE(buildBoundFields(&pDataBlock->boundColumnInfo, pSchema, fieldNum, fields, pDataBlock->pTableMeta->tableInfo.precision));
+ CHECK_CODE(buildBoundFields(&pDataBlock->boundColumnInfo, pSchema, fieldNum, fields,
+ pDataBlock->pTableMeta->tableInfo.precision));
return TSDB_CODE_SUCCESS;
}
@@ -1811,7 +2040,6 @@ int32_t qBuildStmtColFields(void* pBlock, int32_t* fieldNum, TAOS_FIELD_E** fiel
typedef struct SmlExecTableHandle {
SParsedDataColInfo tags; // each table
- SKVRowBuilder tagsBuilder; // each table
SVCreateTbReq createTblReq; // each table
} SmlExecTableHandle;
@@ -1823,7 +2051,6 @@ typedef struct SmlExecHandle {
static void smlDestroyTableHandle(void* pHandle) {
SmlExecTableHandle* handle = (SmlExecTableHandle*)pHandle;
- tdDestroyKVRowBuilder(&handle->tagsBuilder);
destroyBoundColumnInfo(&handle->tags);
destroyCreateSubTbReq(&handle->createTblReq);
}
@@ -1899,30 +2126,68 @@ static int32_t smlBoundColumnData(SArray* cols, SParsedDataColInfo* pColList, SS
return TSDB_CODE_SUCCESS;
}
-static int32_t smlBuildTagRow(SArray* cols, SKVRowBuilder* tagsBuilder, SParsedDataColInfo* tags, SSchema* pSchema,
- SKVRow* row, SMsgBuf* msg) {
- if (tdInitKVRowBuilder(tagsBuilder) < 0) {
+/**
+ * @brief No json tag for schemaless
+ *
+ * @param cols
+ * @param tags
+ * @param pSchema
+ * @param ppTag
+ * @param msg
+ * @return int32_t
+ */
+static int32_t smlBuildTagRow(SArray* cols, SParsedDataColInfo* tags, SSchema* pSchema, STag** ppTag, SMsgBuf* msg) {
+ SArray* pTagArray = taosArrayInit(tags->numOfBound, sizeof(STagVal));
+ if (!pTagArray) {
return TSDB_CODE_TSC_OUT_OF_MEMORY;
}
- SKvParam param = {.builder = tagsBuilder};
+ int32_t code = TSDB_CODE_SUCCESS;
for (int i = 0; i < tags->numOfBound; ++i) {
SSchema* pTagSchema = &pSchema[tags->boundColumns[i]];
- param.schema = pTagSchema;
- SSmlKv* kv = taosArrayGetP(cols, i);
- if (IS_VAR_DATA_TYPE(kv->type)) {
- KvRowAppend(msg, kv->value, kv->length, ¶m);
+ SSmlKv* kv = taosArrayGetP(cols, i);
+
+ STagVal val = {.cid = pTagSchema->colId, .type = pTagSchema->type};
+ if (pTagSchema->type == TSDB_DATA_TYPE_BINARY) {
+ val.pData = (uint8_t*)kv->value;
+ val.nData = kv->length;
+ } else if (pTagSchema->type == TSDB_DATA_TYPE_NCHAR) {
+ int32_t output = 0;
+ void *p = taosMemoryCalloc(1, kv->length * TSDB_NCHAR_SIZE);
+ if(p == NULL){
+ code = TSDB_CODE_OUT_OF_MEMORY;
+ goto end;
+ }
+ if (!taosMbsToUcs4(kv->value, kv->length, (TdUcs4*)(p), kv->length * TSDB_NCHAR_SIZE, &output)) {
+ if (errno == E2BIG) {
+ taosMemoryFree(p);
+ code = generateSyntaxErrMsg(msg, TSDB_CODE_PAR_VALUE_TOO_LONG, pTagSchema->name);
+ goto end;
+ }
+ char buf[512] = {0};
+ snprintf(buf, tListLen(buf), " taosMbsToUcs4 error:%s", strerror(errno));
+ taosMemoryFree(p);
+ code = buildSyntaxErrMsg(msg, buf, kv->value);
+ goto end;
+ }
+ val.pData = p;
+ val.nData = output;
} else {
- KvRowAppend(msg, &(kv->value), kv->length, ¶m);
+ memcpy(&val.i64, &(kv->value), kv->length);
}
+ taosArrayPush(pTagArray, &val);
}
- *row = tdGetKVRowFromBuilder(tagsBuilder);
- if (*row == NULL) {
- return TSDB_CODE_OUT_OF_MEMORY;
+ code = tTagNew(pTagArray, 1, false, ppTag);
+end:
+ for (int i = 0; i < taosArrayGetSize(pTagArray); ++i) {
+ STagVal* p = (STagVal*)taosArrayGet(pTagArray, i);
+ if (p->type == TSDB_DATA_TYPE_NCHAR) {
+ taosMemoryFree(p->pData);
+ }
}
- tdSortKVRowByColIdx(*row);
- return TSDB_CODE_SUCCESS;
+ taosArrayDestroy(pTagArray);
+ return code;
}
int32_t smlBindData(void* handle, SArray* tags, SArray* colsSchema, SArray* cols, bool format, STableMeta* pTableMeta,
@@ -1938,14 +2203,13 @@ int32_t smlBindData(void* handle, SArray* tags, SArray* colsSchema, SArray* cols
buildInvalidOperationMsg(&pBuf, "bound tags error");
return ret;
}
- SKVRow row = NULL;
- ret = smlBuildTagRow(tags, &smlHandle->tableExecHandle.tagsBuilder, &smlHandle->tableExecHandle.tags, pTagsSchema,
- &row, &pBuf);
+ STag* pTag = NULL;
+ ret = smlBuildTagRow(tags, &smlHandle->tableExecHandle.tags, pTagsSchema, &pTag, &pBuf);
if (ret != TSDB_CODE_SUCCESS) {
return ret;
}
- buildCreateTbReq(&smlHandle->tableExecHandle.createTblReq, tableName, row, pTableMeta->suid);
+ buildCreateTbReq(&smlHandle->tableExecHandle.createTblReq, tableName, pTag, pTableMeta->suid);
STableDataBlocks* pDataBlock = NULL;
ret = getDataBlockFromList(smlHandle->pBlockHash, &pTableMeta->uid, sizeof(pTableMeta->uid),
diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c
index b9b3da0dfe..c4e63ee880 100644
--- a/source/libs/parser/src/parTranslater.c
+++ b/source/libs/parser/src/parTranslater.c
@@ -712,7 +712,6 @@ static EDealRes translateValueImpl(STranslateContext* pCxt, SValueNode* pVal, SD
pVal->datum.p = taosMemoryCalloc(1, targetDt.bytes + 1);
if (NULL == pVal->datum.p) {
return generateDealNodeErrMsg(pCxt, TSDB_CODE_OUT_OF_MEMORY);
- ;
}
int32_t len = 0;
@@ -4162,8 +4161,8 @@ static int32_t rewriteCreateTable(STranslateContext* pCxt, SQuery* pQuery) {
return code;
}
-static void addCreateTbReqIntoVgroup(int32_t acctId, SHashObj* pVgroupHashmap, SCreateSubTableClause* pStmt, SKVRow row,
- uint64_t suid, SVgroupInfo* pVgInfo) {
+static void addCreateTbReqIntoVgroup(int32_t acctId, SHashObj* pVgroupHashmap, SCreateSubTableClause* pStmt,
+ const STag* pTag, uint64_t suid, SVgroupInfo* pVgInfo) {
char dbFName[TSDB_DB_FNAME_LEN] = {0};
SName name = {.type = TSDB_DB_NAME_T, .acctId = acctId};
strcpy(name.dbname, pStmt->dbName);
@@ -4173,7 +4172,7 @@ static void addCreateTbReqIntoVgroup(int32_t acctId, SHashObj* pVgroupHashmap, S
req.type = TD_CHILD_TABLE;
req.name = strdup(pStmt->tableName);
req.ctb.suid = suid;
- req.ctb.pTag = row;
+ req.ctb.pTag = (uint8_t*)pTag;
if (pStmt->ignoreExists) {
req.flags |= TD_CREATE_IF_NOT_EXISTS;
}
@@ -4193,24 +4192,6 @@ static void addCreateTbReqIntoVgroup(int32_t acctId, SHashObj* pVgroupHashmap, S
}
}
-static int32_t addValToKVRow(STranslateContext* pCxt, SValueNode* pVal, const SSchema* pSchema,
- SKVRowBuilder* pBuilder) {
- if (pSchema->type == TSDB_DATA_TYPE_JSON) {
- if (pVal->literal && strlen(pVal->literal) > (TSDB_MAX_JSON_TAG_LEN - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE) {
- return buildSyntaxErrMsg(&pCxt->msgBuf, "json string too long than 4095", pVal->literal);
- }
-
- return parseJsontoTagData(pVal->literal, pBuilder, &pCxt->msgBuf, pSchema->colId);
- }
-
- if (pVal->node.resType.type != TSDB_DATA_TYPE_NULL) {
- tdAddColToKVRow(pBuilder, pSchema->colId, nodesGetValueFromNode(pVal),
- IS_VAR_DATA_TYPE(pSchema->type) ? varDataTLen(pVal->datum.p) : TYPE_BYTES[pSchema->type]);
- }
-
- return TSDB_CODE_SUCCESS;
-}
-
static int32_t createValueFromFunction(STranslateContext* pCxt, SFunctionNode* pFunc, SValueNode** pVal) {
int32_t code = getFuncInfo(pCxt, pFunc);
if (TSDB_CODE_SUCCESS == code) {
@@ -4238,15 +4219,22 @@ static int32_t translateTagVal(STranslateContext* pCxt, uint8_t precision, SSche
}
static int32_t buildKVRowForBindTags(STranslateContext* pCxt, SCreateSubTableClause* pStmt, STableMeta* pSuperTableMeta,
- SKVRowBuilder* pBuilder) {
+ STag** ppTag) {
int32_t numOfTags = getNumOfTags(pSuperTableMeta);
if (LIST_LENGTH(pStmt->pValsOfTags) != LIST_LENGTH(pStmt->pSpecificTags) ||
numOfTags < LIST_LENGTH(pStmt->pValsOfTags)) {
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_TAGS_NOT_MATCHED);
}
+ SArray* pTagArray = taosArrayInit(LIST_LENGTH(pStmt->pValsOfTags), sizeof(STagVal));
+ if (!pTagArray) {
+ return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_TSC_OUT_OF_MEMORY);
+ }
+ int32_t code = TSDB_CODE_SUCCESS;
+ int16_t nTags = 0, nBufPos = 0;
SSchema* pTagSchema = getTableTagSchema(pSuperTableMeta);
- SNode * pTag, *pNode;
+ SNode * pTag = NULL, *pNode = NULL;
+ bool isJson = false;
FORBOTH(pTag, pStmt->pSpecificTags, pNode, pStmt->pValsOfTags) {
SColumnNode* pCol = (SColumnNode*)pTag;
SSchema* pSchema = NULL;
@@ -4257,56 +4245,125 @@ static int32_t buildKVRowForBindTags(STranslateContext* pCxt, SCreateSubTableCla
}
}
if (NULL == pSchema) {
- return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_TAG_NAME, pCol->colName);
+ code = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_TAG_NAME, pCol->colName);
+ goto end;
}
SValueNode* pVal = NULL;
- int32_t code = translateTagVal(pCxt, pSuperTableMeta->tableInfo.precision, pSchema, pNode, &pVal);
- if (TSDB_CODE_SUCCESS == code) {
- if (NULL == pVal) {
- pVal = (SValueNode*)pNode;
- } else {
- REPLACE_LIST2_NODE(pVal);
- }
- }
- if (TSDB_CODE_SUCCESS == code) {
- code = addValToKVRow(pCxt, pVal, pSchema, pBuilder);
- }
+ code = translateTagVal(pCxt, pSuperTableMeta->tableInfo.precision, pSchema, pNode, &pVal);
if (TSDB_CODE_SUCCESS != code) {
- return code;
+ goto end;
+ }
+
+ if (NULL == pVal) {
+ pVal = (SValueNode*)pNode;
+ } else {
+ REPLACE_LIST2_NODE(pVal);
+ }
+ if (pTagSchema->type == TSDB_DATA_TYPE_JSON) {
+ if (pVal->literal && strlen(pVal->literal) > (TSDB_MAX_JSON_TAG_LEN - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE) {
+ code = buildSyntaxErrMsg(&pCxt->msgBuf, "json string too long than 4095", pVal->literal);
+ goto end;
+ }
+
+ isJson = true;
+ code = parseJsontoTagData(pVal->literal, pTagArray, ppTag, &pCxt->msgBuf);
+ if(code != TSDB_CODE_SUCCESS){
+ goto end;
+ }
+ }else if (pVal->node.resType.type != TSDB_DATA_TYPE_NULL) {
+ void* nodeVal = nodesGetValueFromNode(pVal);
+ STagVal val = {.cid = pTagSchema->colId, .type = pTagSchema->type};
+ if (IS_VAR_DATA_TYPE(pTagSchema->type)) {
+ val.pData = varDataVal(nodeVal);
+ val.nData = varDataLen(nodeVal);
+ } else {
+ memcpy(&val.i64, nodeVal, pTagSchema->bytes);
+ }
+ taosArrayPush(pTagArray, &val);
}
}
+ if(!isJson) code = tTagNew(pTagArray, 1, false, ppTag);
+
+end:
+ if(isJson){
+ for (int i = 0; i < taosArrayGetSize(pTagArray); ++i) {
+ STagVal *p = (STagVal *)taosArrayGet(pTagArray, i);
+ if(IS_VAR_DATA_TYPE(p->type)){
+ taosMemoryFree(p->pData);
+ }
+ }
+ }
+ taosArrayDestroy(pTagArray);
return TSDB_CODE_SUCCESS;
}
static int32_t buildKVRowForAllTags(STranslateContext* pCxt, SCreateSubTableClause* pStmt, STableMeta* pSuperTableMeta,
- SKVRowBuilder* pBuilder) {
+ STag** ppTag) {
if (getNumOfTags(pSuperTableMeta) != LIST_LENGTH(pStmt->pValsOfTags)) {
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_TAGS_NOT_MATCHED);
}
- SSchema* pTagSchema = getTableTagSchema(pSuperTableMeta);
+ SSchema* pTagSchemas = getTableTagSchema(pSuperTableMeta);
SNode* pNode;
+ int32_t code = TSDB_CODE_SUCCESS;
int32_t index = 0;
+ SArray* pTagArray = taosArrayInit(LIST_LENGTH(pStmt->pValsOfTags), sizeof(STagVal));
+ if (!pTagArray) {
+ return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_TSC_OUT_OF_MEMORY);
+ }
+
+ bool isJson = false;
FOREACH(pNode, pStmt->pValsOfTags) {
SValueNode* pVal = NULL;
- int32_t code = translateTagVal(pCxt, pSuperTableMeta->tableInfo.precision, pTagSchema + index, pNode, &pVal);
- if (TSDB_CODE_SUCCESS == code) {
- if (NULL == pVal) {
- pVal = (SValueNode*)pNode;
- } else {
- REPLACE_NODE(pVal);
- }
- }
- if (TSDB_CODE_SUCCESS == code) {
- code = addValToKVRow(pCxt, pVal, pTagSchema + index++, pBuilder);
- }
+ SSchema* pTagSchema = pTagSchemas + index;
+ code = translateTagVal(pCxt, pSuperTableMeta->tableInfo.precision, pTagSchema, pNode, &pVal);
if (TSDB_CODE_SUCCESS != code) {
- return code;
+ goto end;
+ }
+ if (NULL == pVal) {
+ pVal = (SValueNode*)pNode;
+ } else {
+ REPLACE_NODE(pVal);
+ }
+ if (pTagSchema->type == TSDB_DATA_TYPE_JSON) {
+ if (pVal->literal && strlen(pVal->literal) > (TSDB_MAX_JSON_TAG_LEN - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE) {
+ code = buildSyntaxErrMsg(&pCxt->msgBuf, "json string too long than 4095", pVal->literal);
+ goto end;
+ }
+
+ isJson = true;
+ code = parseJsontoTagData(pVal->literal, pTagArray, ppTag, &pCxt->msgBuf);
+ if(code != TSDB_CODE_SUCCESS){
+ goto end;
+ }
+ }else if (pVal->node.resType.type != TSDB_DATA_TYPE_NULL) {
+ char* tmpVal = nodesGetValueFromNode(pVal);
+ STagVal val = {.cid = pTagSchema->colId, .type = pTagSchema->type};
+ if (IS_VAR_DATA_TYPE(pTagSchema->type)) {
+ val.pData = varDataVal(tmpVal);
+ val.nData = varDataLen(tmpVal);
+ } else {
+ memcpy(&val.i64, tmpVal, pTagSchema->bytes);
+ }
+ taosArrayPush(pTagArray, &val);
+ }
+ ++index;
+ }
+ if(!isJson) code = tTagNew(pTagArray, 1, false, ppTag);
+
+end:
+ if(isJson){
+ for (int i = 0; i < taosArrayGetSize(pTagArray); ++i) {
+ STagVal *p = (STagVal *)taosArrayGet(pTagArray, i);
+ if(IS_VAR_DATA_TYPE(p->type)){
+ taosMemoryFree(p->pData);
+ }
}
}
- return TSDB_CODE_SUCCESS;
+ taosArrayDestroy(pTagArray);
+ return code;
}
static int32_t checkCreateSubTable(STranslateContext* pCxt, SCreateSubTableClause* pStmt) {
@@ -4323,26 +4380,13 @@ static int32_t rewriteCreateSubTable(STranslateContext* pCxt, SCreateSubTableCla
code = getTableMeta(pCxt, pStmt->useDbName, pStmt->useTableName, &pSuperTableMeta);
}
- SKVRowBuilder kvRowBuilder = {0};
- if (TSDB_CODE_SUCCESS == code) {
- code = tdInitKVRowBuilder(&kvRowBuilder);
- }
+ STag* pTag = NULL;
if (TSDB_CODE_SUCCESS == code) {
if (NULL != pStmt->pSpecificTags) {
- code = buildKVRowForBindTags(pCxt, pStmt, pSuperTableMeta, &kvRowBuilder);
+ code = buildKVRowForBindTags(pCxt, pStmt, pSuperTableMeta, &pTag);
} else {
- code = buildKVRowForAllTags(pCxt, pStmt, pSuperTableMeta, &kvRowBuilder);
- }
- }
-
- SKVRow row = NULL;
- if (TSDB_CODE_SUCCESS == code) {
- row = tdGetKVRowFromBuilder(&kvRowBuilder);
- if (NULL == row) {
- code = TSDB_CODE_OUT_OF_MEMORY;
- } else {
- tdSortKVRowByColIdx(row);
+ code = buildKVRowForAllTags(pCxt, pStmt, pSuperTableMeta, &pTag);
}
}
@@ -4351,11 +4395,10 @@ static int32_t rewriteCreateSubTable(STranslateContext* pCxt, SCreateSubTableCla
code = getTableHashVgroup(pCxt, pStmt->dbName, pStmt->tableName, &info);
}
if (TSDB_CODE_SUCCESS == code) {
- addCreateTbReqIntoVgroup(pCxt->pParseCxt->acctId, pVgroupHashmap, pStmt, row, pSuperTableMeta->uid, &info);
+ addCreateTbReqIntoVgroup(pCxt->pParseCxt->acctId, pVgroupHashmap, pStmt, pTag, pSuperTableMeta->uid, &info);
}
taosMemoryFreeClear(pSuperTableMeta);
- tdDestroyKVRowBuilder(&kvRowBuilder);
return code;
}
@@ -4577,37 +4620,41 @@ static int32_t buildUpdateTagValReq(STranslateContext* pCxt, SAlterTableStmt* pS
pReq->isNull = (TSDB_DATA_TYPE_NULL == pStmt->pVal->node.resType.type);
if (pStmt->pVal->node.resType.type == TSDB_DATA_TYPE_JSON) {
- SKVRowBuilder kvRowBuilder = {0};
- int32_t code = tdInitKVRowBuilder(&kvRowBuilder);
-
- if (TSDB_CODE_SUCCESS != code) {
- return TSDB_CODE_OUT_OF_MEMORY;
- }
if (pStmt->pVal->literal &&
strlen(pStmt->pVal->literal) > (TSDB_MAX_JSON_TAG_LEN - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE) {
return buildSyntaxErrMsg(&pCxt->msgBuf, "json string too long than 4095", pStmt->pVal->literal);
}
-
- code = parseJsontoTagData(pStmt->pVal->literal, &kvRowBuilder, &pCxt->msgBuf, pSchema->colId);
- if (TSDB_CODE_SUCCESS != code) {
+ SArray *pTagVals = taosArrayInit(1, sizeof(STagVal));
+ int32_t code = TSDB_CODE_SUCCESS;
+ STag* pTag = NULL;
+ do{
+ code = parseJsontoTagData(pStmt->pVal->literal, pTagVals, &pTag, &pCxt->msgBuf);
+ if (TSDB_CODE_SUCCESS != code) {
+ break;
+ }
+ }while(0);
+ for (int i = 0; i < taosArrayGetSize(pTagVals); ++i) {
+ STagVal *p = (STagVal *)taosArrayGet(pTagVals, i);
+ if(IS_VAR_DATA_TYPE(p->type)){
+ taosMemoryFree(p->pData);
+ }
+ }
+ taosArrayDestroy(pTagVals);
+ if (code != TSDB_CODE_SUCCESS){
return code;
}
-
- SKVRow row = tdGetKVRowFromBuilder(&kvRowBuilder);
- if (NULL == row) {
- tdDestroyKVRowBuilder(&kvRowBuilder);
- return TSDB_CODE_OUT_OF_MEMORY;
- }
- pReq->nTagVal = kvRowLen(row);
- pReq->pTagVal = row;
- pStmt->pVal->datum.p = row; // for free
- tdDestroyKVRowBuilder(&kvRowBuilder);
+ pReq->nTagVal = pTag->len;
+ pReq->pTagVal = (uint8_t *)pTag;
+ pStmt->pVal->datum.p = (char*)pTag; // for free
} else {
pReq->nTagVal = pStmt->pVal->node.resType.bytes;
- if (TSDB_DATA_TYPE_NCHAR == pStmt->pVal->node.resType.type) {
- pReq->nTagVal = pReq->nTagVal * TSDB_NCHAR_SIZE;
- }
pReq->pTagVal = nodesGetValueFromNode(pStmt->pVal);
+
+ // data and length are seperated for new tag format STagVal
+ if (IS_VAR_DATA_TYPE(pStmt->pVal->node.resType.type)) {
+ pReq->nTagVal = varDataLen(pReq->pTagVal);
+ pReq->pTagVal = varDataVal(pReq->pTagVal);
+ }
}
return TSDB_CODE_SUCCESS;
diff --git a/source/libs/parser/src/parUtil.c b/source/libs/parser/src/parUtil.c
index 9882440bbb..0a1915d6c2 100644
--- a/source/libs/parser/src/parUtil.c
+++ b/source/libs/parser/src/parUtil.c
@@ -322,33 +322,35 @@ static bool isValidateTag(char* input) {
return true;
}
-int32_t parseJsontoTagData(const char* json, SKVRowBuilder* kvRowBuilder, SMsgBuf* pMsgBuf, int16_t startColId) {
+int32_t parseJsontoTagData(const char* json, SArray* pTagVals, STag **ppTag, SMsgBuf* pMsgBuf) {
+ int32_t retCode = TSDB_CODE_SUCCESS;
+ cJSON* root = NULL;
+ SHashObj* keyHash = NULL;
+ int32_t size = 0;
// set json NULL data
- uint8_t jsonNULL = TSDB_DATA_TYPE_NULL;
- int32_t jsonIndex = startColId + 1;
if (!json || strtrim((char*)json) == 0 || strcasecmp(json, TSDB_DATA_NULL_STR_L) == 0) {
- tdAddColToKVRow(kvRowBuilder, jsonIndex, &jsonNULL, CHAR_BYTES);
- return TSDB_CODE_SUCCESS;
+ retCode = TSDB_CODE_SUCCESS;
+ goto end;
}
// set json real data
- cJSON* root = cJSON_Parse(json);
+ root = cJSON_Parse(json);
if (root == NULL) {
- return buildSyntaxErrMsg(pMsgBuf, "json parse error", json);
+ retCode = buildSyntaxErrMsg(pMsgBuf, "json parse error", json);
+ goto end;
}
- int32_t size = cJSON_GetArraySize(root);
+ size = cJSON_GetArraySize(root);
if (!cJSON_IsObject(root)) {
- return buildSyntaxErrMsg(pMsgBuf, "json error invalide value", json);
+ retCode = buildSyntaxErrMsg(pMsgBuf, "json error invalide value", json);
+ goto end;
}
- int32_t retCode = 0;
- char* tagKV = NULL;
- SHashObj* keyHash = taosHashInit(8, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, false);
+ keyHash = taosHashInit(8, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, false);
for (int32_t i = 0; i < size; i++) {
cJSON* item = cJSON_GetArrayItem(root, i);
if (!item) {
- qError("json inner error:%d", i);
+ uError("json inner error:%d", i);
retCode = buildSyntaxErrMsg(pMsgBuf, "json inner error", json);
goto end;
}
@@ -360,85 +362,60 @@ int32_t parseJsontoTagData(const char* json, SKVRowBuilder* kvRowBuilder, SMsgBu
}
size_t keyLen = strlen(jsonKey);
if (keyLen > TSDB_MAX_JSON_KEY_LEN) {
- qError("json key too long error");
+ uError("json key too long error");
retCode = buildSyntaxErrMsg(pMsgBuf, "json key too long, more than 256", jsonKey);
goto end;
}
if (keyLen == 0 || taosHashGet(keyHash, jsonKey, keyLen) != NULL) {
continue;
}
- // key: keyLen + VARSTR_HEADER_SIZE, value type: CHAR_BYTES, value reserved: DOUBLE_BYTES
- tagKV = taosMemoryCalloc(keyLen + VARSTR_HEADER_SIZE + CHAR_BYTES + DOUBLE_BYTES, 1);
- if (!tagKV) {
- retCode = TSDB_CODE_TSC_OUT_OF_MEMORY;
- goto end;
- }
- strncpy(varDataVal(tagKV), jsonKey, keyLen);
- varDataSetLen(tagKV, keyLen);
- if (taosHashGetSize(keyHash) == 0) {
- uint8_t jsonNotNULL = TSDB_DATA_TYPE_JSON;
- tdAddColToKVRow(kvRowBuilder, jsonIndex++, &jsonNotNULL, CHAR_BYTES); // add json type
- }
- taosHashPut(keyHash, jsonKey, keyLen, &keyLen,
- CHAR_BYTES); // add key to hash to remove dumplicate, value is useless
+ STagVal val = {0};
+ val.pKey = jsonKey;
+ taosHashPut(keyHash, jsonKey, keyLen, &keyLen, CHAR_BYTES); // add key to hash to remove dumplicate, value is useless
if (item->type == cJSON_String) { // add json value format: type|data
char* jsonValue = item->valuestring;
int32_t valLen = (int32_t)strlen(jsonValue);
- int32_t totalLen = keyLen + VARSTR_HEADER_SIZE + valLen * TSDB_NCHAR_SIZE + VARSTR_HEADER_SIZE + CHAR_BYTES;
- char* tmp = taosMemoryRealloc(tagKV, totalLen);
+ char* tmp = taosMemoryCalloc(1, valLen * TSDB_NCHAR_SIZE);
if (!tmp) {
retCode = TSDB_CODE_TSC_OUT_OF_MEMORY;
goto end;
}
- tagKV = tmp;
- char* valueType = POINTER_SHIFT(tagKV, keyLen + VARSTR_HEADER_SIZE);
- char* valueData = POINTER_SHIFT(tagKV, keyLen + VARSTR_HEADER_SIZE + CHAR_BYTES);
- *valueType = TSDB_DATA_TYPE_NCHAR;
- if (valLen > 0 && !taosMbsToUcs4(jsonValue, valLen, (TdUcs4*)varDataVal(valueData),
+ val.type = TSDB_DATA_TYPE_NCHAR;
+ if (valLen > 0 && !taosMbsToUcs4(jsonValue, valLen, (TdUcs4*)tmp,
(int32_t)(valLen * TSDB_NCHAR_SIZE), &valLen)) {
- qError("charset:%s to %s. val:%s, errno:%s, convert failed.", DEFAULT_UNICODE_ENCODEC, tsCharset, jsonValue,
+ uError("charset:%s to %s. val:%s, errno:%s, convert failed.", DEFAULT_UNICODE_ENCODEC, tsCharset, jsonValue,
strerror(errno));
retCode = buildSyntaxErrMsg(pMsgBuf, "charset convert json error", jsonValue);
goto end;
}
-
- varDataSetLen(valueData, valLen);
- tdAddColToKVRow(kvRowBuilder, jsonIndex++, tagKV, totalLen);
+ val.nData = valLen;
+ val.pData = tmp;
} else if (item->type == cJSON_Number) {
if (!isfinite(item->valuedouble)) {
- qError("json value is invalidate");
+ uError("json value is invalidate");
retCode = buildSyntaxErrMsg(pMsgBuf, "json value number is illegal", json);
goto end;
}
- char* valueType = POINTER_SHIFT(tagKV, keyLen + VARSTR_HEADER_SIZE);
- char* valueData = POINTER_SHIFT(tagKV, keyLen + VARSTR_HEADER_SIZE + CHAR_BYTES);
- *valueType = TSDB_DATA_TYPE_DOUBLE;
- *((double*)valueData) = item->valuedouble;
- tdAddColToKVRow(kvRowBuilder, jsonIndex++, tagKV, keyLen + VARSTR_HEADER_SIZE + CHAR_BYTES + DOUBLE_BYTES);
+ val.type = TSDB_DATA_TYPE_DOUBLE;
+ *((double*)&(val.i64)) = item->valuedouble;
} else if (item->type == cJSON_True || item->type == cJSON_False) {
- char* valueType = POINTER_SHIFT(tagKV, keyLen + VARSTR_HEADER_SIZE);
- char* valueData = POINTER_SHIFT(tagKV, keyLen + VARSTR_HEADER_SIZE + CHAR_BYTES);
- *valueType = TSDB_DATA_TYPE_BOOL;
- *valueData = (char)(item->valueint);
- tdAddColToKVRow(kvRowBuilder, jsonIndex++, tagKV, keyLen + VARSTR_HEADER_SIZE + CHAR_BYTES + CHAR_BYTES);
+ val.type = TSDB_DATA_TYPE_BOOL;
+ *((char*)&(val.i64)) = (char)(item->valueint);
} else if (item->type == cJSON_NULL) {
- char* valueType = POINTER_SHIFT(tagKV, keyLen + VARSTR_HEADER_SIZE);
- *valueType = TSDB_DATA_TYPE_NULL;
- tdAddColToKVRow(kvRowBuilder, jsonIndex++, tagKV, keyLen + VARSTR_HEADER_SIZE + CHAR_BYTES);
+ val.type = TSDB_DATA_TYPE_NULL;
} else {
retCode = buildSyntaxErrMsg(pMsgBuf, "invalidate json value", json);
goto end;
}
- }
-
- if (taosHashGetSize(keyHash) == 0) { // set json NULL true
- tdAddColToKVRow(kvRowBuilder, jsonIndex, &jsonNULL, CHAR_BYTES);
+ taosArrayPush(pTagVals, &val);
}
end:
- taosMemoryFree(tagKV);
taosHashCleanup(keyHash);
+ if(retCode == TSDB_CODE_SUCCESS){
+ tTagNew(pTagVals, 1, true, ppTag);
+ }
cJSON_Delete(root);
return retCode;
}
diff --git a/source/libs/parser/test/mockCatalog.cpp b/source/libs/parser/test/mockCatalog.cpp
index 154f13ea68..8fb28ce395 100644
--- a/source/libs/parser/test/mockCatalog.cpp
+++ b/source/libs/parser/test/mockCatalog.cpp
@@ -188,8 +188,8 @@ int32_t __catalogGetDBVgVersion(SCatalog* pCtg, const char* dbFName, int32_t* ve
}
int32_t __catalogGetDBVgInfo(SCatalog* pCtg, void* pRpc, const SEpSet* pMgmtEps, const char* dbFName,
- SArray** vgroupList) {
- return 0;
+ SArray** pVgList) {
+ return g_mockCatalogService->catalogGetDBVgInfo(dbFName, pVgList);
}
int32_t __catalogGetDBCfg(SCatalog* pCtg, void* pRpc, const SEpSet* pMgmtEps, const char* dbFName, SDbCfgInfo* pDbCfg) {
diff --git a/source/libs/parser/test/mockCatalogService.cpp b/source/libs/parser/test/mockCatalogService.cpp
index 566c4d8b04..4834d2d377 100644
--- a/source/libs/parser/test/mockCatalogService.cpp
+++ b/source/libs/parser/test/mockCatalogService.cpp
@@ -18,6 +18,7 @@
#include
#include
#include