Merge branch '3.0' into merge/mainto3.0
This commit is contained in:
commit
488434771b
|
@ -243,6 +243,8 @@ The effective value of charset is UTF-8.
|
|||
| concurrentCheckpoint | |Supported, effective immediately | Internal parameter, whether to check checkpoints concurrently |
|
||||
| maxStreamBackendCache | |Supported, effective immediately | Internal parameter, maximum cache used by stream computing |
|
||||
| streamSinkDataRate | |Supported, effective after restart| Internal parameter, used to control the write speed of stream computing results |
|
||||
| streamNotifyMessageSize | After 3.3.6.0 | Not supported | Internal parameter, controls the message size for event notifications, default value is 8192 |
|
||||
| streamNotifyFrameSize | After 3.3.6.0 | Not supported | Internal parameter, controls the underlying frame size when sending event notification messages, default value is 256 |
|
||||
|
||||
### Log Related
|
||||
|
||||
|
|
|
@ -55,9 +55,9 @@ join_clause:
|
|||
|
||||
window_clause: {
|
||||
SESSION(ts_col, tol_val)
|
||||
| STATE_WINDOW(col)
|
||||
| STATE_WINDOW(col) [TRUE_FOR(true_for_duration)]
|
||||
| INTERVAL(interval_val [, interval_offset]) [SLIDING (sliding_val)] [WATERMARK(watermark_val)] [FILL(fill_mod_and_val)]
|
||||
| EVENT_WINDOW START WITH start_trigger_condition END WITH end_trigger_condition
|
||||
| EVENT_WINDOW START WITH start_trigger_condition END WITH end_trigger_condition [TRUE_FOR(true_for_duration)]
|
||||
| COUNT_WINDOW(count_val[, sliding_val])
|
||||
|
||||
interp_clause:
|
||||
|
|
|
@ -2125,6 +2125,28 @@ UNIQUE(expr)
|
|||
|
||||
**Applicable to**: Tables and supertables.
|
||||
|
||||
### COLS
|
||||
|
||||
```sql
|
||||
COLS(func(expr), output_expr1, [, output_expr2] ... )
|
||||
```
|
||||
|
||||
**Function Description**: On the data row where the execution result of function func(expr) is located, execute the expression output_expr1, [, output_expr2], return its result, and the result of func (expr) is not output.
|
||||
|
||||
**Return Data Type**: Returns multiple columns of data, and the data type of each column is the type of the result returned by the corresponding expression.
|
||||
|
||||
**Applicable Data Types**: All type fields.
|
||||
|
||||
**Applicable to**: Tables and Super Tables.
|
||||
|
||||
**Usage Instructions**:
|
||||
- Func function type: must be a single-line selection function (output result is a single-line selection function, for example, last is a single-line selection function, but top is a multi-line selection function).
|
||||
- Mainly used to obtain the associated columns of multiple selection function results in a single SQL query. For example: select cols(max(c0), ts), cols(max(c1), ts) from ... can be used to get the different ts values of the maximum values of columns c0 and c1.
|
||||
- The result of the parameter func is not returned. If you need to output the result of func, you can add additional output columns, such as: select first(ts), cols(first(ts), c1) from ..
|
||||
- When there is only one column in the output, you can set an alias for the function. For example, you can do it like this: "select cols(first (ts), c1) as c11 from ...".
|
||||
- Output one or more columns, and you can set an alias for each output column of the function. For example, you can do it like this: "select (first (ts), c1 as c11, c2 as c22) from ...".
|
||||
|
||||
|
||||
## Time-Series Specific Functions
|
||||
|
||||
Time-Series specific functions are tailor-made by TDengine to meet the query scenarios of time-series data. In general databases, implementing similar functionalities usually requires complex query syntax and is inefficient. TDengine has built these functionalities into functions, greatly reducing the user's cost of use.
|
||||
|
|
|
@ -53,9 +53,9 @@ The syntax for the window clause is as follows:
|
|||
```sql
|
||||
window_clause: {
|
||||
SESSION(ts_col, tol_val)
|
||||
| STATE_WINDOW(col)
|
||||
| STATE_WINDOW(col) [TRUE_FOR(true_for_duration)]
|
||||
| INTERVAL(interval_val [, interval_offset]) [SLIDING (sliding_val)] [FILL(fill_mod_and_val)]
|
||||
| EVENT_WINDOW START WITH start_trigger_condition END WITH end_trigger_condition
|
||||
| EVENT_WINDOW START WITH start_trigger_condition END WITH end_trigger_condition [TRUE_FOR(true_for_duration)]
|
||||
| COUNT_WINDOW(count_val[, sliding_val])
|
||||
}
|
||||
```
|
||||
|
@ -177,6 +177,12 @@ TDengine also supports using CASE expressions in state quantities, which can exp
|
|||
SELECT tbname, _wstart, CASE WHEN voltage >= 205 and voltage <= 235 THEN 1 ELSE 0 END status FROM meters PARTITION BY tbname STATE_WINDOW(CASE WHEN voltage >= 205 and voltage <= 235 THEN 1 ELSE 0 END);
|
||||
```
|
||||
|
||||
The state window supports using the TRUE_FOR parameter to set its minimum duration. If the window's duration is less than the specified value, it will be discarded automatically and no result will be returned. For example, setting the minimum duration to 3 seconds:
|
||||
|
||||
```
|
||||
SELECT COUNT(*), FIRST(ts), status FROM temp_tb_1 STATE_WINDOW(status) TRUE_FOR (3s);
|
||||
```
|
||||
|
||||
### Session Window
|
||||
|
||||
The session window is determined based on the timestamp primary key values of the records. As shown in the diagram below, if the continuous interval of the timestamps is set to be less than or equal to 12 seconds, the following 6 records form 2 session windows, which are: [2019-04-28 14:22:10, 2019-04-28 14:22:30] and [2019-04-28 14:23:10, 2019-04-28 14:23:30]. This is because the interval between 2019-04-28 14:22:30 and 2019-04-28 14:23:10 is 40 seconds, exceeding the continuous interval (12 seconds).
|
||||
|
@ -212,6 +218,12 @@ select _wstart, _wend, count(*) from t event_window start with c1 > 0 end with c
|
|||
<Image img={imgStep04} alt=""/>
|
||||
</figure>
|
||||
|
||||
The event window supports using the TRUE_FOR parameter to set its minimum duration. If the window's duration is less than the specified value, it will be discarded automatically and no result will be returned. For example, setting the minimum duration to 3 seconds:
|
||||
|
||||
```
|
||||
select _wstart, _wend, count(*) from t event_window start with c1 > 0 end with c2 < 10 true_for (3s);
|
||||
```
|
||||
|
||||
### Count Window
|
||||
|
||||
Count windows divide data into windows based on a fixed number of data rows. By default, data is sorted by timestamp, then divided into multiple windows based on the value of count_val, and aggregate calculations are performed. count_val represents the maximum number of data rows in each count window; if the total number of data rows is not divisible by count_val, the last window will have fewer rows than count_val. sliding_val is a constant that represents the number of rows the window slides, similar to the SLIDING in interval.
|
||||
|
|
|
@ -458,6 +458,12 @@ This document details the server error codes that may be encountered when using
|
|||
| 0x80002665 | The _TAGS pseudocolumn can only be used for subtable and supertable queries | Illegal tag column query | Check and correct the SQL statement |
|
||||
| 0x80002666 | Subquery does not output primary timestamp column | Check and correct the SQL statement | |
|
||||
| 0x80002667 | Invalid usage of expr: %s | Illegal expression | Check and correct the SQL statement |
|
||||
| 0x80002687 | True_for duration cannot be negative | Use negative value as true_for duration | Check and correct the SQL statement |
|
||||
| 0x80002688 | Cannot use 'year' or 'month' as true_for duration | Use year or month as true_for_duration | Check and correct the SQL statement |
|
||||
| 0x80002680 | Invalid using cols function | Illegal using cols function | Check and correct the SQL statement |
|
||||
| 0x8000268A | Cols function's first param must be a select function that output a single row | The first parameter of the cols function should be a selection function | Check and correct the SQL statement |
|
||||
| 0x8000268B | Invalid using cols function with multiple output columns | Illegal using the cols function for multiple column output | Check and correct the SQL statement |
|
||||
| 0x8000268C | Invalid using alias for cols function | Illegal cols function alias | Check and correct the SQL statement |
|
||||
| 0x800026FF | Parser internal error | Internal error in parser | Preserve the scene and logs, report issue on GitHub |
|
||||
| 0x80002700 | Planner internal error | Internal error in planner | Preserve the scene and logs, report issue on GitHub |
|
||||
| 0x80002701 | Expect ts equal | JOIN condition validation failed | Preserve the scene and logs, report issue on GitHub |
|
||||
|
|
|
@ -45,7 +45,7 @@ TDengine 消费者的概念跟 Kafka 类似,消费者通过订阅主题来接
|
|||
| `max.poll.interval.ms` | integer | consumer poll 拉取数据间隔的最长时间,超过该时间,会认为该 consumer 离线,触发 rebalance 逻辑,成功后该 consumer 会被删除(从 3.3.3.0 版本开始支持) | 默认值为 300000,[1000,INT32_MAX] |
|
||||
| `fetch.max.wait.ms` | integer | 服务端单次返回数据的最大耗时(从 3.3.6.0 版本开始支持) | 默认值为 1000,[1,INT32_MAX] |
|
||||
| `min.poll.rows` | integer | 服务端单次返回数据的最小条数(从 3.3.6.0 版本开始支持) | 默认值为 4096,[1,INT32_MAX] |
|
||||
| `msg.consume.rawdata` | integer | 消费数据时拉取数据类型为二进制类型,不可做解析操作,内部参数,只用于 taosx 数据迁移(从3.3.6.0版本开始支持) | 默认值为 0 表示不起效, 非 0 为 起效 |
|
||||
| `msg.consume.rawdata` | integer | 消费数据时拉取数据类型为二进制类型,不可做解析操作,内部参数,只用于 taosX 数据迁移(从 3.3.6.0 版本开始支持) | 默认值为 0 表示不起效, 非 0 为 起效 |
|
||||
|
||||
|
||||
下面是各语言连接器创建参数:
|
||||
|
|
|
@ -1067,6 +1067,26 @@ charset 的有效值是 UTF-8。
|
|||
- 动态修改:支持通过 SQL 修改,立即生效
|
||||
- 支持版本:从 v3.1.0.0 版本开始引入
|
||||
|
||||
#### streamNotifyMessageSize
|
||||
- 说明:用于控制事件通知的消息大小 `内部参数`
|
||||
- 类型:整数
|
||||
- 单位:KB
|
||||
- 默认值:8192
|
||||
- 最小值:8
|
||||
- 最大值:1048576
|
||||
- 动态修改:不支持
|
||||
- 支持版本:从 v3.3.6.0 版本开始引入
|
||||
|
||||
#### streamNotifyFrameSize
|
||||
- 说明:用于控制事件通知消息发送时底层的帧大小 `内部参数`
|
||||
- 类型:整数
|
||||
- 单位:KB
|
||||
- 默认值:256
|
||||
- 最小值:8
|
||||
- 最大值:1048576
|
||||
- 动态修改:不支持
|
||||
- 支持版本:从 v3.3.6.0 版本开始引入
|
||||
|
||||
### 日志相关
|
||||
|
||||
#### logDir
|
||||
|
|
|
@ -115,9 +115,9 @@ taosBenchmark -f <json file>
|
|||
|
||||
- **continue_if_fail** : 允许用户定义失败后行为。
|
||||
|
||||
“continue_if_fail”: “no”, 失败 taosBenchmark 自动退出,默认行为。
|
||||
“continue_if_fail”: “yes”, 失败 taosBenchmark 警告用户,并继续写入。
|
||||
“continue_if_fail”: “smart”, 如果子表不存在失败,taosBenchmark 会建立子表并继续写入。
|
||||
"continue_if_fail": "no", 失败 taosBenchmark 自动退出,默认行为。
|
||||
"continue_if_fail": "yes", 失败 taosBenchmark 警告用户,并继续写入。
|
||||
"continue_if_fail": "smart", 如果子表不存在失败,taosBenchmark 会建立子表并继续写入。
|
||||
|
||||
#### 数据库相关
|
||||
|
||||
|
@ -125,7 +125,7 @@ taosBenchmark -f <json file>
|
|||
|
||||
- **name** : 数据库名。
|
||||
|
||||
- **drop** : 数据库已存在时是否删除,可选项为 "yes" 或 "no", 默认为 “yes” 。
|
||||
- **drop** : 数据库已存在时是否删除,可选项为 "yes" 或 "no", 默认为 "yes" 。
|
||||
|
||||
#### 超级表相关
|
||||
|
||||
|
@ -208,7 +208,7 @@ taosBenchmark -f <json file>
|
|||
|
||||
- **scalingFactor** : 浮点数精度增强因子,仅当数据类型是 float/double 时生效,有效值范围为 1 至 1000000 的正整数。用于增强生成浮点数的精度,特别是在 min 或 max 值较小的情况下。此属性按 10 的幂次增强小数点后的精度:scalingFactor 为 10 表示增强 1 位小数精度,100 表示增强 2 位,依此类推。
|
||||
|
||||
- **fun** : 此列数据以函数填充,目前只支持 sin 和 cos 两函数,输入参数为时间戳换算成角度值,换算公式: 角度 x = 输入的时间列ts值 % 360。同时支持系数调节,随机波动因子调节,以固定格式的表达式展现,如 fun=“10\*sin(x)+100\*random(5)” , x 表示角度,取值 0 ~ 360度,增长步长与时间列步长一致。10 表示乘的系数,100 表示加或减的系数,5 表示波动幅度在 5% 的随机范围内。目前支持的数据类型为 int, bigint, float, double 四种数据类型。注意:表达式为固定模式,不可前后颠倒。
|
||||
- **fun** : 此列数据以函数填充,目前只支持 sin 和 cos 两函数,输入参数为时间戳换算成角度值,换算公式: 角度 x = 输入的时间列ts值 % 360。同时支持系数调节,随机波动因子调节,以固定格式的表达式展现,如 fun="10\*sin(x)+100\*random(5)" , x 表示角度,取值 0 ~ 360度,增长步长与时间列步长一致。10 表示乘的系数,100 表示加或减的系数,5 表示波动幅度在 5% 的随机范围内。目前支持的数据类型为 int, bigint, float, double 四种数据类型。注意:表达式为固定模式,不可前后颠倒。
|
||||
|
||||
- **values** : nchar/binary 列/标签的值域,将从值中随机选择。
|
||||
|
||||
|
@ -220,15 +220,15 @@ taosBenchmark -f <json file>
|
|||
|
||||
- **level**: 字符串类型,指定此列两级压缩中的第二级加密算法的压缩率高低,详细参见创建超级表。
|
||||
|
||||
- **gen**: 字符串类型,指定此列生成数据的方式,不指定为随机,若指定为 “order”, 会按自然数顺序增长。
|
||||
- **gen**: 字符串类型,指定此列生成数据的方式,不指定为随机,若指定为 "order", 会按自然数顺序增长。
|
||||
|
||||
- **fillNull**: 字符串类型,指定此列是否随机插入 NULL 值,可指定为 “true” 或 "false", 只有当 generate_row_rule 为 2 时有效。
|
||||
- **fillNull**: 字符串类型,指定此列是否随机插入 NULL 值,可指定为 "true" 或 "false", 只有当 generate_row_rule 为 2 时有效。
|
||||
|
||||
#### 写入行为相关
|
||||
|
||||
- **thread_count** : 插入数据的线程数量,默认为 8。
|
||||
|
||||
- **thread_bind_vgroup** : 写入时 vgroup 是否和写入线程绑定,绑定后可提升写入速度, 取值为 "yes" 或 "no",默认值为 “no”, 设置为 “no” 后与原来行为一致。 当设为 “yes” 时,如果 thread_count 大于写入数据库 vgroups 数量, thread_count 自动调整为 vgroups 数量;如果 thread_count 小于 vgroups 数量,写入线程数量不做调整,一个线程写完一个 vgroup 数据后再写下一个,同时保持一个 vgroup 同时只能由一个线程写入的规则。
|
||||
- **thread_bind_vgroup** : 写入时 vgroup 是否和写入线程绑定,绑定后可提升写入速度, 取值为 "yes" 或 "no",默认值为 "no", 设置为 "no" 后与原来行为一致。 当设为 "yes" 时,如果 thread_count 大于写入数据库 vgroups 数量, thread_count 自动调整为 vgroups 数量;如果 thread_count 小于 vgroups 数量,写入线程数量不做调整,一个线程写完一个 vgroup 数据后再写下一个,同时保持一个 vgroup 同时只能由一个线程写入的规则。
|
||||
|
||||
- **create_table_thread_count** : 建表的线程数量,默认为 8。
|
||||
|
||||
|
@ -248,7 +248,7 @@ taosBenchmark -f <json file>
|
|||
|
||||
- **prepare_rand** : 生成的随机数据中唯一值的数量。若为 1 则表示所有数据都相同。默认值为 10000 。
|
||||
|
||||
- **pre_load_tb_meta** :是否提前加载子表的 meta 数据,取值为 “yes” or "no"。当子表数量非常多时,打开此选项可提高写入速度。
|
||||
- **pre_load_tb_meta** :是否提前加载子表的 meta 数据,取值为 "yes" or "no"。当子表数量非常多时,打开此选项可提高写入速度。
|
||||
|
||||
### 查询配置参数
|
||||
|
||||
|
@ -265,7 +265,7 @@ interval 控制休眠时间,避免持续查询慢查询消耗 CPU ,单位为
|
|||
查询指定表(可以指定超级表、子表或普通表)的配置参数在 `specified_table_query` 中设置。
|
||||
|
||||
- **mixed_query** : 查询模式
|
||||
“yes” :`混合查询`
|
||||
"yes" :`混合查询`
|
||||
"no"(默认值) :`普通查询`
|
||||
`普通查询`:`sqls` 中每个 sql 启动 `threads` 个线程查询此 sql, 执行完 `query_times` 次查询后退出,执行此 sql 的所有线程都完成后进入下一个 sql
|
||||
`查询总次数` = `sqls` 个数 * `query_times` * `threads`
|
||||
|
|
|
@ -56,9 +56,9 @@ join_clause:
|
|||
|
||||
window_clause: {
|
||||
SESSION(ts_col, tol_val)
|
||||
| STATE_WINDOW(col)
|
||||
| STATE_WINDOW(col) [TRUE_FOR(true_for_duration)]
|
||||
| INTERVAL(interval_val [, interval_offset]) [SLIDING (sliding_val)] [WATERMARK(watermark_val)] [FILL(fill_mod_and_val)]
|
||||
| EVENT_WINDOW START WITH start_trigger_condition END WITH end_trigger_condition
|
||||
| EVENT_WINDOW START WITH start_trigger_condition END WITH end_trigger_condition [TRUE_FOR(true_for_duration)]
|
||||
| COUNT_WINDOW(count_val[, sliding_val])
|
||||
|
||||
interp_clause:
|
||||
|
|
|
@ -2049,6 +2049,27 @@ UNIQUE(expr)
|
|||
|
||||
**适用于**:表和超级表。
|
||||
|
||||
### COLS
|
||||
|
||||
```sql
|
||||
COLS(func(expr), output_expr1, [, output_expr2] ... )
|
||||
```
|
||||
|
||||
**功能说明**:在选择函数 func(expr) 执行结果所在数据行上,执行表达式 output_expr1, [, output_expr2],返回其结果,func(expr)结果不输出。
|
||||
|
||||
**返回数据类型**:返回多列数据,每列数据类型为对应表达式返回结果的类型。
|
||||
|
||||
**适用数据类型**:全部类型字段。
|
||||
|
||||
**适用于**:表和超级表。
|
||||
|
||||
**使用说明:**
|
||||
- func 函数类型:必须是单行选择函数(输出结果为一行的选择函数,例如 last 是单行选择函数, 但 top 是多行选择函数)。
|
||||
- 主要用于一个 sql 中获取多个选择函数结果关联列的场景,例如: select cols(max(c0), ts), cols(max(c1), ts) from ...可用于获取 c0, c1 列最大值的不同 ts 值。
|
||||
- 注意, 函数 func 的结果并没有返回,如需输出 func 结果,可额外增加输出列,如: select fist(ts), cols(first(ts), c1) from ...
|
||||
- 输出只有一列时,可以对 cols 函数设置别名。例如: "select cols(first(ts), c1) as c11 from ..."
|
||||
- 输出一列或者多列时,可以对 cols 函数的每个输出列设置命名。例如: "select cols(first(ts), c1 as c11, c2 as c22)"
|
||||
|
||||
|
||||
## 时序数据特有函数
|
||||
|
||||
|
|
|
@ -46,9 +46,9 @@ TDengine 支持按时间窗口切分方式进行聚合结果查询,比如温
|
|||
```sql
|
||||
window_clause: {
|
||||
SESSION(ts_col, tol_val)
|
||||
| STATE_WINDOW(col)
|
||||
| STATE_WINDOW(col) [TRUE_FOR(true_for_duration)]
|
||||
| INTERVAL(interval_val [, interval_offset]) [SLIDING (sliding_val)] [FILL(fill_mod_and_val)]
|
||||
| EVENT_WINDOW START WITH start_trigger_condition END WITH end_trigger_condition
|
||||
| EVENT_WINDOW START WITH start_trigger_condition END WITH end_trigger_condition [TRUE_FOR(true_for_duration)]
|
||||
| COUNT_WINDOW(count_val[, sliding_val])
|
||||
}
|
||||
```
|
||||
|
@ -165,6 +165,12 @@ TDengine 还支持将 CASE 表达式用在状态量,可以表达某个状态
|
|||
SELECT tbname, _wstart, CASE WHEN voltage >= 205 and voltage <= 235 THEN 1 ELSE 0 END status FROM meters PARTITION BY tbname STATE_WINDOW(CASE WHEN voltage >= 205 and voltage <= 235 THEN 1 ELSE 0 END);
|
||||
```
|
||||
|
||||
状态窗口支持使用 TRUE_FOR 参数来设定窗口的最小持续时长。如果某个状态窗口的宽度低于该设定值,则会自动舍弃,不返回任何计算结果。例如,设置最短持续时长为 3s:
|
||||
|
||||
```
|
||||
SELECT COUNT(*), FIRST(ts), status FROM temp_tb_1 STATE_WINDOW(status) TRUE_FOR (3s);
|
||||
```
|
||||
|
||||
### 会话窗口
|
||||
|
||||
会话窗口根据记录的时间戳主键的值来确定是否属于同一个会话。如下图所示,如果设置时间戳的连续的间隔小于等于 12 秒,则以下 6 条记录构成 2 个会话窗口,分别是:[2019-04-28 14:22:10,2019-04-28 14:22:30]和[2019-04-28 14:23:10,2019-04-28 14:23:30]。因为 2019-04-28 14:22:30 与 2019-04-28 14:23:10 之间的时间间隔是 40 秒,超过了连续时间间隔(12 秒)。
|
||||
|
@ -196,6 +202,12 @@ select _wstart, _wend, count(*) from t event_window start with c1 > 0 end with c
|
|||
|
||||

|
||||
|
||||
事件窗口支持使用 TRUE_FOR 参数来设定窗口的最小持续时长。如果某个事件窗口的宽度低于该设定值,则会自动舍弃,不返回任何计算结果。例如,设置最短持续时长为 3s:
|
||||
|
||||
```
|
||||
select _wstart, _wend, count(*) from t event_window start with c1 > 0 end with c2 < 10 true_for (3s);
|
||||
```
|
||||
|
||||
### 计数窗口
|
||||
|
||||
计数窗口按固定的数据行数来划分窗口。默认将数据按时间戳排序,再按照count_val的值,将数据划分为多个窗口,然后做聚合计算。count_val表示每个count window包含的最大数据行数,总数据行数不能整除count_val时,最后一个窗口的行数会小于count_val。sliding_val是常量,表示窗口滑动的数量,类似于 interval的SLIDING。
|
||||
|
|
|
@ -77,6 +77,7 @@ description: TDengine 保留关键字的详细列表
|
|||
| CLIENT_VERSION | |
|
||||
| CLUSTER | |
|
||||
| COLON | |
|
||||
| COLS | |
|
||||
| COLUMN | |
|
||||
| COMMA | |
|
||||
| COMMENT | |
|
||||
|
@ -427,6 +428,7 @@ description: TDengine 保留关键字的详细列表
|
|||
| TRANSACTIONS | |
|
||||
| TRIGGER | |
|
||||
| TRIM | |
|
||||
| TRUE_FOR | |
|
||||
| TSDB_PAGESIZE | |
|
||||
| TSERIES | |
|
||||
| TSMA | |
|
||||
|
|
|
@ -475,6 +475,12 @@ description: TDengine 服务端的错误码列表和详细说明
|
|||
| 0x80002665 | The _TAGS pseudo column can only be used for subtable and supertable queries | 非法TAG列查询 | 检查并修正 SQL 语句 |
|
||||
| 0x80002666 | 子查询不含主键时间戳列输出 | 检查并修正 SQL 语句 |
|
||||
| 0x80002667 | Invalid usage of expr: %s | 非法表达式 | 检查并修正 SQL 语句 |
|
||||
| 0x80002687 | True_for duration cannot be negative | true_for 的值不能是负数 | 检查并修正 SQL 语句 |
|
||||
| 0x80002688 | Cannot use 'year' or 'month' as true_for duration | 不能使用 n(月), y(年) 作为 true_for 的时间单位 | 检查并修正 SQL 语句 |
|
||||
| 0x80002689 | Invalid using cols function | cols函数使用错误 | 检查并修正 SQL 语句 |
|
||||
| 0x8000268A | Cols function's first param must be a select function that output a single row | cols函数第一个参数应该为选择函数 | 检查并修正 SQL 语句 |
|
||||
| 0x8000268B | Invalid using cols function with multiple output columns | 多列输出的 cols 函数使用错误 | 检查并修正 SQL 语句 |
|
||||
| 0x8000268C | Invalid using alias for cols function | cols 函数输出列重命名错误 | 检查并修正 SQL 语句 |
|
||||
| 0x800026FF | Parser internal error | 解析器内部错误 | 保留现场和日志,github上报issue |
|
||||
| 0x80002700 | Planner internal error | 计划期内部错误 | 保留现场和日志,github上报issue |
|
||||
| 0x80002701 | Expect ts equal | JOIN条件校验失败 | 保留现场和日志,github上报issue |
|
||||
|
|
|
@ -276,12 +276,14 @@ typedef struct tExprNode {
|
|||
int32_t num;
|
||||
struct SFunctionNode *pFunctNode;
|
||||
int32_t functionType;
|
||||
int32_t bindExprID;
|
||||
} _function;
|
||||
|
||||
struct {
|
||||
struct SNode *pRootNode;
|
||||
} _optrRoot;
|
||||
};
|
||||
int32_t relatedTo;
|
||||
} tExprNode;
|
||||
|
||||
struct SScalarParam {
|
||||
|
|
|
@ -155,6 +155,7 @@ typedef enum EFunctionType {
|
|||
FUNCTION_TYPE_FORECAST_LOW,
|
||||
FUNCTION_TYPE_FORECAST_HIGH,
|
||||
FUNCTION_TYPE_FORECAST_ROWTS,
|
||||
FUNCTION_TYPE_COLS,
|
||||
FUNCTION_TYPE_IROWTS_ORIGIN,
|
||||
|
||||
// internal function
|
||||
|
@ -208,6 +209,7 @@ typedef enum EFunctionType {
|
|||
FUNCTION_TYPE_HYPERLOGLOG_STATE,
|
||||
FUNCTION_TYPE_HYPERLOGLOG_STATE_MERGE,
|
||||
|
||||
|
||||
// geometry functions
|
||||
FUNCTION_TYPE_GEOM_FROM_TEXT = 4250,
|
||||
FUNCTION_TYPE_AS_TEXT,
|
||||
|
@ -295,6 +297,7 @@ bool fmisSelectGroupConstValueFunc(int32_t funcId);
|
|||
bool fmIsElapsedFunc(int32_t funcId);
|
||||
bool fmIsDBUsageFunc(int32_t funcId);
|
||||
bool fmIsRowTsOriginFunc(int32_t funcId);
|
||||
bool fmIsSelectColsFunc(int32_t funcId);
|
||||
|
||||
void getLastCacheDataType(SDataType* pType, int32_t pkBytes);
|
||||
int32_t createFunction(const char* pName, SNodeList* pParameterList, SFunctionNode** pFunc);
|
||||
|
|
|
@ -327,6 +327,7 @@ typedef struct SWindowLogicNode {
|
|||
SNode* pStateExpr;
|
||||
SNode* pStartCond;
|
||||
SNode* pEndCond;
|
||||
int64_t trueForLimit;
|
||||
int8_t triggerType;
|
||||
int64_t watermark;
|
||||
int64_t deleteMark;
|
||||
|
@ -724,6 +725,7 @@ typedef SSessionWinodwPhysiNode SStreamFinalSessionWinodwPhysiNode;
|
|||
typedef struct SStateWinodwPhysiNode {
|
||||
SWindowPhysiNode window;
|
||||
SNode* pStateKey;
|
||||
int64_t trueForLimit;
|
||||
} SStateWinodwPhysiNode;
|
||||
|
||||
typedef SStateWinodwPhysiNode SStreamStateWinodwPhysiNode;
|
||||
|
@ -732,6 +734,7 @@ typedef struct SEventWinodwPhysiNode {
|
|||
SWindowPhysiNode window;
|
||||
SNode* pStartCond;
|
||||
SNode* pEndCond;
|
||||
int64_t trueForLimit;
|
||||
} SEventWinodwPhysiNode;
|
||||
|
||||
typedef SEventWinodwPhysiNode SStreamEventWinodwPhysiNode;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#ifndef _TD_QUERY_NODES_H_
|
||||
#define _TD_QUERY_NODES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -61,6 +62,8 @@ typedef struct SExprNode {
|
|||
bool asParam;
|
||||
bool asPosition;
|
||||
int32_t projIdx;
|
||||
int32_t relatedTo;
|
||||
int32_t bindExprID;
|
||||
} SExprNode;
|
||||
|
||||
typedef enum EColumnType {
|
||||
|
@ -322,6 +325,7 @@ typedef struct SStateWindowNode {
|
|||
ENodeType type; // QUERY_NODE_STATE_WINDOW
|
||||
SNode* pCol; // timestamp primary key
|
||||
SNode* pExpr;
|
||||
SNode* pTrueForLimit;
|
||||
} SStateWindowNode;
|
||||
|
||||
typedef struct SSessionWindowNode {
|
||||
|
@ -346,6 +350,7 @@ typedef struct SEventWindowNode {
|
|||
SNode* pCol; // timestamp primary key
|
||||
SNode* pStartCond;
|
||||
SNode* pEndCond;
|
||||
SNode* pTrueForLimit;
|
||||
} SEventWindowNode;
|
||||
|
||||
typedef struct SCountWindowNode {
|
||||
|
@ -428,6 +433,7 @@ typedef struct SSelectStmt {
|
|||
ENodeType type; // QUERY_NODE_SELECT_STMT
|
||||
bool isDistinct;
|
||||
SNodeList* pProjectionList;
|
||||
SNodeList* pProjectionBindList;
|
||||
SNode* pFromTable;
|
||||
SNode* pWhere;
|
||||
SNodeList* pPartitionByList;
|
||||
|
@ -697,6 +703,9 @@ char* getJoinSTypeString(EJoinSubType type);
|
|||
char* getFullJoinTypeString(EJoinType type, EJoinSubType stype);
|
||||
int32_t mergeJoinConds(SNode** ppDst, SNode** ppSrc);
|
||||
|
||||
void rewriteExprAliasName(SExprNode* pNode, int64_t num);
|
||||
bool isRelatedToOtherExpr(SExprNode* pExpr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -129,6 +129,7 @@ size_t taosWriteToCFile(const void *ptr, size_t size, size_t nitems, FILE *strea
|
|||
int taosCloseCFile(FILE *);
|
||||
int taosSetAutoDelFile(char *path);
|
||||
|
||||
FILE *taosOpenFileForStream(const char *path, int32_t tdFileOptions);
|
||||
bool lastErrorIsFileNotExist();
|
||||
|
||||
#ifdef BUILD_WITH_RAND_ERR
|
||||
|
|
|
@ -908,6 +908,12 @@ int32_t taosGetErrSize();
|
|||
#define TSDB_CODE_PAR_INVALID_ANOMALY_WIN_OPT TAOS_DEF_ERROR_CODE(0, 0x2684)
|
||||
#define TSDB_CODE_PAR_INVALID_FORECAST_CLAUSE TAOS_DEF_ERROR_CODE(0, 0x2685)
|
||||
#define TSDB_CODE_PAR_INVALID_VGID_LIST TAOS_DEF_ERROR_CODE(0, 0x2686)
|
||||
#define TSDB_CODE_PAR_TRUE_FOR_NEGATIVE TAOS_DEF_ERROR_CODE(0, 0x2687)
|
||||
#define TSDB_CODE_PAR_TRUE_FOR_UNIT TAOS_DEF_ERROR_CODE(0, 0x2688)
|
||||
#define TSDB_CODE_PAR_INVALID_COLS_FUNCTION TAOS_DEF_ERROR_CODE(0, 0x2689)
|
||||
#define TSDB_CODE_PAR_INVALID_COLS_SELECTFUNC TAOS_DEF_ERROR_CODE(0, 0x268A)
|
||||
#define TSDB_CODE_INVALID_MULITI_COLS_FUNC TAOS_DEF_ERROR_CODE(0, 0x268B)
|
||||
#define TSDB_CODE_INVALID_COLS_ALIAS TAOS_DEF_ERROR_CODE(0, 0x268C)
|
||||
#define TSDB_CODE_PAR_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x26FF)
|
||||
|
||||
//planner
|
||||
|
|
|
@ -266,6 +266,7 @@ typedef enum ELogicConditionType {
|
|||
#define TSDB_SUBSCRIBE_KEY_LEN (TSDB_CGROUP_LEN + TSDB_TOPIC_FNAME_LEN + 2)
|
||||
#define TSDB_PARTITION_KEY_LEN (TSDB_SUBSCRIBE_KEY_LEN + 20)
|
||||
#define TSDB_COL_NAME_LEN 65
|
||||
#define TSDB_COL_NAME_EXLEN 8
|
||||
#define TSDB_COL_FNAME_LEN (TSDB_TABLE_NAME_LEN + TSDB_COL_NAME_LEN + TSDB_NAME_DELIMITER_LEN)
|
||||
#define TSDB_MAX_SAVED_SQL_LEN TSDB_MAX_COLUMNS * 64
|
||||
#define TSDB_MAX_SQL_LEN TSDB_PAYLOAD_SIZE
|
||||
|
|
|
@ -1510,7 +1510,7 @@ TEST(clientCase, sub_tb_mt_test) {
|
|||
(void)taosThreadCreate(&qid[i], NULL, doConsumeData, NULL);
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < 4; ++i) {
|
||||
for (int32_t i = 0; i < 1; ++i) {
|
||||
(void)taosThreadJoin(qid[i], NULL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,32 +3,23 @@ MESSAGE(STATUS "build parser unit test")
|
|||
|
||||
# GoogleTest requires at least C++11
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} SOURCE_LIST)
|
||||
|
||||
ADD_EXECUTABLE(commonTest "")
|
||||
TARGET_SOURCES(
|
||||
commonTest
|
||||
PRIVATE
|
||||
"commonTests.cpp"
|
||||
)
|
||||
TARGET_LINK_LIBRARIES(
|
||||
commonTest
|
||||
PUBLIC os util common gtest
|
||||
)
|
||||
|
||||
TARGET_INCLUDE_DIRECTORIES(
|
||||
if(TD_LINUX)
|
||||
add_executable(commonTest "commonTests.cpp")
|
||||
target_link_libraries(commonTest os util common gtest_main)
|
||||
target_include_directories(
|
||||
commonTest
|
||||
PUBLIC "${TD_SOURCE_DIR}/include/libs/common/"
|
||||
PRIVATE "${TD_SOURCE_DIR}/source/libs/common/inc"
|
||||
)
|
||||
add_test(
|
||||
NAME commonTest
|
||||
COMMAND commonTest
|
||||
)
|
||||
endif()
|
||||
|
||||
# dataformatTest.cpp
|
||||
add_executable(dataformatTest "")
|
||||
target_sources(
|
||||
dataformatTest
|
||||
PRIVATE
|
||||
"dataformatTest.cpp"
|
||||
)
|
||||
add_executable(dataformatTest "dataformatTest.cpp")
|
||||
target_link_libraries(dataformatTest gtest gtest_main util common)
|
||||
target_include_directories(
|
||||
dataformatTest
|
||||
|
@ -41,12 +32,7 @@ add_test(
|
|||
)
|
||||
|
||||
# cosCpTest.cpp
|
||||
add_executable(cosCpTest "")
|
||||
target_sources(
|
||||
cosCpTest
|
||||
PRIVATE
|
||||
"cosCpTest.cpp"
|
||||
)
|
||||
add_executable(cosCpTest "cosCpTest.cpp")
|
||||
target_link_libraries(cosCpTest gtest gtest_main util common)
|
||||
target_include_directories(
|
||||
cosCpTest
|
||||
|
@ -59,14 +45,8 @@ add_test(
|
|||
)
|
||||
|
||||
if(TD_LINUX)
|
||||
|
||||
# cosTest.cpp
|
||||
add_executable(cosTest "")
|
||||
target_sources(
|
||||
cosTest
|
||||
PRIVATE
|
||||
"cosTest.cpp"
|
||||
)
|
||||
add_executable(cosTest "cosTest.cpp")
|
||||
target_link_libraries(cosTest gtest gtest_main util common)
|
||||
target_include_directories(
|
||||
cosTest
|
||||
|
@ -77,7 +57,6 @@ add_test(
|
|||
NAME cosTest
|
||||
COMMAND cosTest
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
if(${TD_LINUX})
|
||||
|
|
|
@ -235,6 +235,57 @@ TEST(testCase, toInteger_test) {
|
|||
ASSERT_EQ(ret, -1);
|
||||
}
|
||||
|
||||
TEST(testCase, Datablock_test_inc) {
|
||||
{
|
||||
SColumnInfoData cinfo = {0};
|
||||
uint32_t row = 0;
|
||||
|
||||
bool ret = colDataIsNull_s(&cinfo, row);
|
||||
EXPECT_EQ(ret, false);
|
||||
|
||||
cinfo.hasNull = 1;
|
||||
cinfo.info.type = TSDB_DATA_TYPE_INT;
|
||||
ret = colDataIsNull_s(&cinfo, row);
|
||||
EXPECT_EQ(ret, false);
|
||||
}
|
||||
|
||||
{
|
||||
SColumnInfoData cinfo = {0};
|
||||
uint32_t row = 0;
|
||||
bool isVarType = false;
|
||||
|
||||
bool ret = colDataIsNull_t(&cinfo, row, isVarType);
|
||||
EXPECT_EQ(ret, false);
|
||||
|
||||
cinfo.hasNull = 1;
|
||||
ret = colDataIsNull_t(&cinfo, row, isVarType);
|
||||
EXPECT_EQ(ret, false);
|
||||
}
|
||||
|
||||
{
|
||||
SColumnInfoData cinfo = {0};
|
||||
uint32_t totalRows = 0;
|
||||
uint32_t row = 0;
|
||||
SColumnDataAgg colAgg = {0};
|
||||
|
||||
bool ret = colDataIsNull(&cinfo, totalRows, row, &colAgg);
|
||||
EXPECT_EQ(ret, false);
|
||||
|
||||
cinfo.hasNull = 1;
|
||||
ret = colDataIsNull(&cinfo, totalRows, row, &colAgg);
|
||||
EXPECT_EQ(ret, true);
|
||||
|
||||
totalRows = 1;
|
||||
ret = colDataIsNull(&cinfo, totalRows, row, &colAgg);
|
||||
EXPECT_EQ(ret, false);
|
||||
|
||||
colAgg.colId = -1;
|
||||
cinfo.info.type = TSDB_DATA_TYPE_INT;
|
||||
ret = colDataIsNull(&cinfo, totalRows, row, &colAgg);
|
||||
EXPECT_EQ(ret, false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(testCase, Datablock_test) {
|
||||
SSDataBlock* b = NULL;
|
||||
int32_t code = createDataBlock(&b);
|
||||
|
@ -288,7 +339,7 @@ TEST(testCase, Datablock_test) {
|
|||
|
||||
printf("binary column length:%d\n", *(int32_t*)p1->pData);
|
||||
|
||||
ASSERT_EQ(blockDataGetNumOfCols(b), 2);
|
||||
ASSERT_EQ(blockDataGetNumOfCols(b), 3);
|
||||
ASSERT_EQ(blockDataGetNumOfRows(b), 40);
|
||||
|
||||
char* pData = colDataGetData(p1, 3);
|
||||
|
@ -639,12 +690,14 @@ TEST(timeTest, char2ts) {
|
|||
ASSERT_EQ(-2, TEST_char2ts("yyyyMM/dd ", &ts, TSDB_TIME_PRECISION_MICRO, "210011/32"));
|
||||
ASSERT_EQ(-1, TEST_char2ts("HH12:MI:SS", &ts, TSDB_TIME_PRECISION_MICRO, "21:12:12"));
|
||||
ASSERT_EQ(-1, TEST_char2ts("yyyy/MM1/dd ", &ts, TSDB_TIME_PRECISION_MICRO, "2100111111111/11/2"));
|
||||
ASSERT_EQ(-2, TEST_char2ts("yyyy/MM1/ddTZH", &ts, TSDB_TIME_PRECISION_MICRO, "23/11/2-13"));
|
||||
|
||||
TEST_char2ts("yyyy/MM1/ddTZH", &ts, TSDB_TIME_PRECISION_MICRO, "23/11/2-13");
|
||||
// ASSERT_EQ(-2, TEST_char2ts("yyyy/MM1/ddTZH", &ts, TSDB_TIME_PRECISION_MICRO, "23/11/2-13"));
|
||||
ASSERT_EQ(0, TEST_char2ts("yyyy年 MM/ddTZH", &ts, TSDB_TIME_PRECISION_MICRO, "1970年1/1+0"));
|
||||
ASSERT_EQ(ts, 0);
|
||||
// ASSERT_EQ(ts, 0);
|
||||
ASSERT_EQ(-1, TEST_char2ts("yyyy年a MM/dd", &ts, TSDB_TIME_PRECISION_MICRO, "2023年1/2"));
|
||||
ASSERT_EQ(0, TEST_char2ts("yyyy年 MM/ddTZH", &ts, TSDB_TIME_PRECISION_MICRO, "1970年 1/1+0"));
|
||||
ASSERT_EQ(ts, 0);
|
||||
// ASSERT_EQ(ts, 0);
|
||||
ASSERT_EQ(0, TEST_char2ts("yyyy年 a a a MM/ddTZH", &ts, TSDB_TIME_PRECISION_MICRO, "1970年 a a a 1/1+0"));
|
||||
ASSERT_EQ(0, TEST_char2ts("yyyy年 a a a a a a a a a a a a a a a MM/ddTZH", &ts, TSDB_TIME_PRECISION_MICRO,
|
||||
"1970年 a "));
|
||||
|
@ -847,8 +900,8 @@ TEST(TaosSetSlowLogScopeTest, InvalidScopeInput) {
|
|||
char pScopeStr[] = "invalid";
|
||||
int32_t scope = 0;
|
||||
int32_t result = taosSetSlowLogScope(pScopeStr, &scope);
|
||||
EXPECT_EQ(result, TSDB_CODE_SUCCESS);
|
||||
EXPECT_EQ(scope, -1);
|
||||
// EXPECT_EQ(result, TSDB_CODE_SUCCESS);
|
||||
// EXPECT_EQ(scope, -1);
|
||||
}
|
||||
|
||||
TEST(TaosSetSlowLogScopeTest, MixedScopesInput) {
|
||||
|
|
|
@ -41,7 +41,7 @@ int32_t sendSyncReq(const SEpSet *pEpSet, SRpcMsg *pMsg) {
|
|||
}
|
||||
|
||||
char *i642str(int64_t val) {
|
||||
static char str[24] = {0};
|
||||
static threadlocal char str[24] = {0};
|
||||
(void)snprintf(str, sizeof(str), "%" PRId64, val);
|
||||
return str;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ typedef struct SGroupResInfo {
|
|||
int32_t index; // rows consumed in func:doCopyToSDataBlockXX
|
||||
int32_t iter; // relate to index-1, last consumed data's slot id in hash table
|
||||
void* dataPos; // relate to index-1, last consumed data's position, in the nodelist of cur slot
|
||||
int32_t delIndex; // rows consumed in func:doBuildDeleteDataBlock
|
||||
SArray* pRows; // SArray<SResKeyPos>
|
||||
char* pBuf;
|
||||
bool freeItem;
|
||||
|
|
|
@ -686,6 +686,54 @@ typedef struct SResultWindowInfo {
|
|||
bool isOutput;
|
||||
} SResultWindowInfo;
|
||||
|
||||
typedef struct SSessionAggOperatorInfo {
|
||||
SOptrBasicInfo binfo;
|
||||
SAggSupporter aggSup;
|
||||
SExprSupp scalarSupp; // supporter for perform scalar function
|
||||
SGroupResInfo groupResInfo;
|
||||
SWindowRowsSup winSup;
|
||||
bool reptScan; // next round scan
|
||||
int64_t gap; // session window gap
|
||||
int32_t tsSlotId; // primary timestamp slot id
|
||||
STimeWindowAggSupp twAggSup;
|
||||
struct SOperatorInfo* pOperator;
|
||||
bool cleanGroupResInfo;
|
||||
} SSessionAggOperatorInfo;
|
||||
|
||||
typedef struct SStateWindowOperatorInfo {
|
||||
SOptrBasicInfo binfo;
|
||||
SAggSupporter aggSup;
|
||||
SExprSupp scalarSup;
|
||||
SGroupResInfo groupResInfo;
|
||||
SWindowRowsSup winSup;
|
||||
SColumn stateCol; // start row index
|
||||
bool hasKey;
|
||||
SStateKeys stateKey;
|
||||
int32_t tsSlotId; // primary timestamp column slot id
|
||||
STimeWindowAggSupp twAggSup;
|
||||
struct SOperatorInfo* pOperator;
|
||||
bool cleanGroupResInfo;
|
||||
int64_t trueForLimit;
|
||||
} SStateWindowOperatorInfo;
|
||||
|
||||
|
||||
typedef struct SEventWindowOperatorInfo {
|
||||
SOptrBasicInfo binfo;
|
||||
SAggSupporter aggSup;
|
||||
SExprSupp scalarSup;
|
||||
SWindowRowsSup winSup;
|
||||
int32_t tsSlotId; // primary timestamp column slot id
|
||||
STimeWindowAggSupp twAggSup;
|
||||
uint64_t groupId; // current group id, used to identify the data block from different groups
|
||||
SFilterInfo* pStartCondInfo;
|
||||
SFilterInfo* pEndCondInfo;
|
||||
bool inWindow;
|
||||
SResultRow* pRow;
|
||||
SSDataBlock* pPreDataBlock;
|
||||
struct SOperatorInfo* pOperator;
|
||||
int64_t trueForLimit;
|
||||
} SEventWindowOperatorInfo;
|
||||
|
||||
typedef struct SStreamSessionAggOperatorInfo {
|
||||
SOptrBasicInfo binfo;
|
||||
SSteamOpBasicInfo basic;
|
||||
|
@ -746,6 +794,7 @@ typedef struct SStreamStateAggOperatorInfo {
|
|||
SSHashObj* pPkDeleted;
|
||||
bool destHasPrimaryKey;
|
||||
struct SOperatorInfo* pOperator;
|
||||
int64_t trueForLimit;
|
||||
} SStreamStateAggOperatorInfo;
|
||||
|
||||
typedef struct SStreamEventAggOperatorInfo {
|
||||
|
@ -778,6 +827,7 @@ typedef struct SStreamEventAggOperatorInfo {
|
|||
struct SOperatorInfo* pOperator;
|
||||
SNodeList* pStartCondCols;
|
||||
SNodeList* pEndCondCols;
|
||||
int64_t trueForLimit;
|
||||
} SStreamEventAggOperatorInfo;
|
||||
|
||||
typedef struct SStreamCountAggOperatorInfo {
|
||||
|
@ -1052,7 +1102,8 @@ int32_t saveSessionOutputBuf(SStreamAggSupporter* pAggSup, SResultWindowInfo* pW
|
|||
int32_t saveResult(SResultWindowInfo winInfo, SSHashObj* pStUpdated);
|
||||
int32_t saveDeleteRes(SSHashObj* pStDelete, SSessionKey key);
|
||||
void removeSessionResult(SStreamAggSupporter* pAggSup, SSHashObj* pHashMap, SSHashObj* pResMap, SSessionKey* pKey);
|
||||
void doBuildDeleteDataBlock(struct SOperatorInfo* pOp, SSHashObj* pStDeleted, SSDataBlock* pBlock, void** Ite);
|
||||
void doBuildDeleteDataBlock(struct SOperatorInfo* pOp, SSHashObj* pStDeleted, SSDataBlock* pBlock, void** Ite,
|
||||
SGroupResInfo* pGroupResInfo);
|
||||
void doBuildSessionResult(struct SOperatorInfo* pOperator, void* pState, SGroupResInfo* pGroupResInfo,
|
||||
SSDataBlock* pBlock, SArray* pSessionKeys);
|
||||
int32_t getSessionWindowInfoByKey(SStreamAggSupporter* pAggSup, SSessionKey* pKey, SResultWindowInfo* pWinInfo);
|
||||
|
@ -1109,6 +1160,7 @@ int32_t getNextQualifiedWindow(SInterval* pInterval, STimeWindow* pNext, SDataBl
|
|||
int32_t extractQualifiedTupleByFilterResult(SSDataBlock* pBlock, const SColumnInfoData* p, int32_t status);
|
||||
bool getIgoreNullRes(SExprSupp* pExprSup);
|
||||
bool checkNullRow(SExprSupp* pExprSup, SSDataBlock* pSrcBlock, int32_t index, bool ignoreNull);
|
||||
int64_t getMinWindowSize(struct SOperatorInfo* pOperator);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "filter.h"
|
||||
#include "function.h"
|
||||
#include "nodes.h"
|
||||
#include "os.h"
|
||||
#include "querynodes.h"
|
||||
#include "tfill.h"
|
||||
|
|
|
@ -24,22 +24,6 @@
|
|||
#include "tdatablock.h"
|
||||
#include "ttime.h"
|
||||
|
||||
typedef struct SEventWindowOperatorInfo {
|
||||
SOptrBasicInfo binfo;
|
||||
SAggSupporter aggSup;
|
||||
SExprSupp scalarSup;
|
||||
SWindowRowsSup winSup;
|
||||
int32_t tsSlotId; // primary timestamp column slot id
|
||||
STimeWindowAggSupp twAggSup;
|
||||
uint64_t groupId; // current group id, used to identify the data block from different groups
|
||||
SFilterInfo* pStartCondInfo;
|
||||
SFilterInfo* pEndCondInfo;
|
||||
bool inWindow;
|
||||
SResultRow* pRow;
|
||||
SSDataBlock* pPreDataBlock;
|
||||
SOperatorInfo* pOperator;
|
||||
} SEventWindowOperatorInfo;
|
||||
|
||||
static int32_t eventWindowAggregateNext(SOperatorInfo* pOperator, SSDataBlock** pRes);
|
||||
static void destroyEWindowOperatorInfo(void* param);
|
||||
static int32_t eventWindowAggImpl(SOperatorInfo* pOperator, SEventWindowOperatorInfo* pInfo, SSDataBlock* pBlock);
|
||||
|
@ -114,8 +98,9 @@ int32_t createEventwindowOperatorInfo(SOperatorInfo* downstream, SPhysiNode* phy
|
|||
pInfo->tsSlotId = tsSlotId;
|
||||
pInfo->pPreDataBlock = NULL;
|
||||
pInfo->pOperator = pOperator;
|
||||
pInfo->trueForLimit = pEventWindowNode->trueForLimit;
|
||||
|
||||
setOperatorInfo(pOperator, "EventWindowOperator", QUERY_NODE_PHYSICAL_PLAN_MERGE_STATE, true, OP_NOT_OPENED, pInfo,
|
||||
setOperatorInfo(pOperator, "EventWindowOperator", QUERY_NODE_PHYSICAL_PLAN_MERGE_EVENT, true, OP_NOT_OPENED, pInfo,
|
||||
pTaskInfo);
|
||||
pOperator->fpSet = createOperatorFpSet(optrDummyOpenFn, eventWindowAggregateNext, NULL, destroyEWindowOperatorInfo,
|
||||
optrDefaultBufFn, NULL, optrDefaultGetNextExtFn, NULL);
|
||||
|
@ -297,6 +282,7 @@ int32_t eventWindowAggImpl(SOperatorInfo* pOperator, SEventWindowOperatorInfo* p
|
|||
TSKEY* tsList = (TSKEY*)pColInfoData->pData;
|
||||
SWindowRowsSup* pRowSup = &pInfo->winSup;
|
||||
int32_t rowIndex = 0;
|
||||
int64_t minWindowSize = getMinWindowSize(pOperator);
|
||||
|
||||
pRowSup->numOfRows = 0;
|
||||
if (pInfo->groupId == 0) {
|
||||
|
@ -341,6 +327,10 @@ int32_t eventWindowAggImpl(SOperatorInfo* pOperator, SEventWindowOperatorInfo* p
|
|||
QUERY_CHECK_CODE(code, lino, _return);
|
||||
doUpdateNumOfRows(pSup->pCtx, pInfo->pRow, pSup->numOfExprs, pSup->rowEntryInfoOffset);
|
||||
|
||||
if (pRowSup->win.ekey - pRowSup->win.skey < minWindowSize) {
|
||||
qDebug("skip small window, groupId: %" PRId64 ", windowSize: %" PRId64 ", minWindowSize: %" PRId64,
|
||||
pInfo->groupId, pRowSup->win.ekey - pRowSup->win.skey, minWindowSize);
|
||||
} else {
|
||||
// check buffer size
|
||||
if (pRes->info.rows + pInfo->pRow->numOfRows >= pRes->info.capacity) {
|
||||
int32_t newSize = pRes->info.rows + pInfo->pRow->numOfRows;
|
||||
|
@ -353,6 +343,7 @@ int32_t eventWindowAggImpl(SOperatorInfo* pOperator, SEventWindowOperatorInfo* p
|
|||
QUERY_CHECK_CODE(code, lino, _return);
|
||||
|
||||
pRes->info.rows += pInfo->pRow->numOfRows;
|
||||
}
|
||||
pInfo->pRow->numOfRows = 0;
|
||||
|
||||
pInfo->inWindow = false;
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include "index.h"
|
||||
#include "os.h"
|
||||
#include "query.h"
|
||||
#include "querynodes.h"
|
||||
#include "tarray.h"
|
||||
#include "tdatablock.h"
|
||||
#include "thash.h"
|
||||
#include "tmsg.h"
|
||||
|
@ -212,6 +214,7 @@ void cleanupGroupResInfo(SGroupResInfo* pGroupResInfo) {
|
|||
pGroupResInfo->pRows = NULL;
|
||||
}
|
||||
pGroupResInfo->index = 0;
|
||||
pGroupResInfo->delIndex = 0;
|
||||
}
|
||||
|
||||
int32_t resultrowComparAsc(const void* p1, const void* p2) {
|
||||
|
@ -303,6 +306,7 @@ void initMultiResInfoFromArrayList(SGroupResInfo* pGroupResInfo, SArray* pArrayL
|
|||
pGroupResInfo->freeItem = true;
|
||||
pGroupResInfo->pRows = pArrayList;
|
||||
pGroupResInfo->index = 0;
|
||||
pGroupResInfo->delIndex = 0;
|
||||
}
|
||||
|
||||
bool hasRemainResults(SGroupResInfo* pGroupResInfo) {
|
||||
|
@ -1956,6 +1960,7 @@ int32_t createExprFromOneNode(SExprInfo* pExp, SNode* pNode, int16_t slotId) {
|
|||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
}
|
||||
}
|
||||
pExp->pExpr->_function.bindExprID = ((SExprNode*)pNode)->bindExprID;
|
||||
} else if (type == QUERY_NODE_OPERATOR) {
|
||||
pExp->pExpr->nodeType = QUERY_NODE_OPERATOR;
|
||||
SOperatorNode* pOpNode = (SOperatorNode*)pNode;
|
||||
|
@ -1993,7 +1998,7 @@ int32_t createExprFromOneNode(SExprInfo* pExp, SNode* pNode, int16_t slotId) {
|
|||
code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
|
||||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
}
|
||||
|
||||
pExp->pExpr->relatedTo = ((SExprNode*)pNode)->relatedTo;
|
||||
_end:
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
|
@ -2074,42 +2079,78 @@ int32_t createExprInfo(SNodeList* pNodeList, SNodeList* pGroupKeys, SExprInfo**
|
|||
return code;
|
||||
}
|
||||
|
||||
static void deleteSubsidiareCtx(void* pData) {
|
||||
SSubsidiaryResInfo* pCtx = (SSubsidiaryResInfo*)pData;
|
||||
if (pCtx->pCtx) {
|
||||
taosMemoryFreeClear(pCtx->pCtx);
|
||||
}
|
||||
}
|
||||
|
||||
// set the output buffer for the selectivity + tag query
|
||||
static int32_t setSelectValueColumnInfo(SqlFunctionCtx* pCtx, int32_t numOfOutput) {
|
||||
int32_t num = 0;
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
int32_t lino = 0;
|
||||
|
||||
SqlFunctionCtx* p = NULL;
|
||||
SqlFunctionCtx** pValCtx = taosMemoryCalloc(numOfOutput, POINTER_BYTES);
|
||||
if (pValCtx == NULL) {
|
||||
SArray* pValCtxArray = NULL;
|
||||
for (int32_t i = numOfOutput - 1; i > 0; --i) { // select Func is at the end of the list
|
||||
int32_t funcIdx = pCtx[i].pExpr->pExpr->_function.bindExprID;
|
||||
if (funcIdx > 0) {
|
||||
if (pValCtxArray == NULL) {
|
||||
// the end of the list is the select function of biggest index
|
||||
pValCtxArray = taosArrayInit_s(sizeof(SSubsidiaryResInfo*), funcIdx);
|
||||
if (pValCtxArray == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
}
|
||||
if (funcIdx > pValCtxArray->size) {
|
||||
qError("funcIdx:%d is out of range", funcIdx);
|
||||
taosArrayDestroyP(pValCtxArray, deleteSubsidiareCtx);
|
||||
return TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
|
||||
}
|
||||
SSubsidiaryResInfo* pSubsidiary = &pCtx[i].subsidiaries;
|
||||
pSubsidiary->pCtx = taosMemoryCalloc(numOfOutput, POINTER_BYTES);
|
||||
if (pSubsidiary->pCtx == NULL) {
|
||||
taosArrayDestroyP(pValCtxArray, deleteSubsidiareCtx);
|
||||
return terrno;
|
||||
}
|
||||
pSubsidiary->num = 0;
|
||||
taosArraySet(pValCtxArray, funcIdx - 1, &pSubsidiary);
|
||||
}
|
||||
}
|
||||
|
||||
SHashObj* pSelectFuncs = taosHashInit(8, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_ENTRY_LOCK);
|
||||
QUERY_CHECK_NULL(pSelectFuncs, code, lino, _end, terrno);
|
||||
SqlFunctionCtx* p = NULL;
|
||||
SqlFunctionCtx** pValCtx = NULL;
|
||||
if (pValCtxArray == NULL) {
|
||||
pValCtx = taosMemoryCalloc(numOfOutput, POINTER_BYTES);
|
||||
if (pValCtx == NULL) {
|
||||
QUERY_CHECK_CODE(terrno, lino, _end);
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < numOfOutput; ++i) {
|
||||
const char* pName = pCtx[i].pExpr->pExpr->_function.functionName;
|
||||
if ((strcmp(pName, "_select_value") == 0) || (strcmp(pName, "_group_key") == 0) ||
|
||||
(strcmp(pName, "_group_const_value") == 0)) {
|
||||
if ((strcmp(pName, "_select_value") == 0)) {
|
||||
if (pValCtxArray == NULL) {
|
||||
pValCtx[num++] = &pCtx[i];
|
||||
} else if (fmIsSelectFunc(pCtx[i].functionId)) {
|
||||
void* data = taosHashGet(pSelectFuncs, pName, strlen(pName));
|
||||
if (taosHashGetSize(pSelectFuncs) != 0 && data == NULL) {
|
||||
p = NULL;
|
||||
break;
|
||||
} else {
|
||||
int32_t tempRes = taosHashPut(pSelectFuncs, pName, strlen(pName), &num, sizeof(num));
|
||||
if (tempRes != TSDB_CODE_SUCCESS && tempRes != TSDB_CODE_DUP_KEY) {
|
||||
code = tempRes;
|
||||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
int32_t bindFuncIndex = pCtx[i].pExpr->pExpr->relatedTo; // start from index 1;
|
||||
if (bindFuncIndex > 0) { // 0 is default index related to the select function
|
||||
bindFuncIndex -= 1;
|
||||
}
|
||||
SSubsidiaryResInfo** pSubsidiary = taosArrayGet(pValCtxArray, bindFuncIndex);
|
||||
if(pSubsidiary == NULL) {
|
||||
QUERY_CHECK_CODE(TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR, lino, _end);
|
||||
}
|
||||
(*pSubsidiary)->pCtx[(*pSubsidiary)->num] = &pCtx[i];
|
||||
(*pSubsidiary)->num++;
|
||||
}
|
||||
} else if (fmIsSelectFunc(pCtx[i].functionId)) {
|
||||
if (pValCtxArray == NULL) {
|
||||
p = &pCtx[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
taosHashCleanup(pSelectFuncs);
|
||||
|
||||
if (p != NULL) {
|
||||
p->subsidiaries.pCtx = pValCtx;
|
||||
|
@ -2120,9 +2161,11 @@ static int32_t setSelectValueColumnInfo(SqlFunctionCtx* pCtx, int32_t numOfOutpu
|
|||
|
||||
_end:
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
taosArrayDestroyP(pValCtxArray, deleteSubsidiareCtx);
|
||||
taosMemoryFreeClear(pValCtx);
|
||||
taosHashCleanup(pSelectFuncs);
|
||||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
} else {
|
||||
taosArrayDestroy(pValCtxArray);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,8 @@ static void doApplyScalarCalculation(SOperatorInfo* pOperator, SSDataBlock* p
|
|||
static int32_t doSetInputDataBlock(SExprSupp* pExprSup, SSDataBlock* pBlock, int32_t order, int32_t scanFlag,
|
||||
bool createDummyCol);
|
||||
static void doCopyToSDataBlock(SExecTaskInfo* pTaskInfo, SSDataBlock* pBlock, SExprSupp* pSup, SDiskbasedBuf* pBuf,
|
||||
SGroupResInfo* pGroupResInfo, int32_t threshold, bool ignoreGroup);
|
||||
SGroupResInfo* pGroupResInfo, int32_t threshold, bool ignoreGroup,
|
||||
int64_t minWindowSize);
|
||||
|
||||
SResultRow* getNewResultRow(SDiskbasedBuf* pResultBuf, int32_t* currentPageId, int32_t interBufSize) {
|
||||
SFilePage* pData = NULL;
|
||||
|
@ -846,7 +847,7 @@ _end:
|
|||
}
|
||||
|
||||
void doCopyToSDataBlock(SExecTaskInfo* pTaskInfo, SSDataBlock* pBlock, SExprSupp* pSup, SDiskbasedBuf* pBuf,
|
||||
SGroupResInfo* pGroupResInfo, int32_t threshold, bool ignoreGroup) {
|
||||
SGroupResInfo* pGroupResInfo, int32_t threshold, bool ignoreGroup, int64_t minWindowSize) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
int32_t lino = 0;
|
||||
SExprInfo* pExprInfo = pSup->pExprInfo;
|
||||
|
@ -874,6 +875,14 @@ void doCopyToSDataBlock(SExecTaskInfo* pTaskInfo, SSDataBlock* pBlock, SExprSupp
|
|||
releaseBufPage(pBuf, page);
|
||||
continue;
|
||||
}
|
||||
// skip the window which is less than the windowMinSize
|
||||
if (pRow->win.ekey - pRow->win.skey < minWindowSize) {
|
||||
qDebug("skip small window, groupId: %" PRId64 ", windowSize: %" PRId64 ", minWindowSize: %" PRId64, pPos->groupId,
|
||||
pRow->win.ekey - pRow->win.skey, minWindowSize);
|
||||
pGroupResInfo->index += 1;
|
||||
releaseBufPage(pBuf, page);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ignoreGroup) {
|
||||
if (pBlock->info.id.groupId == 0) {
|
||||
|
@ -937,11 +946,11 @@ void doBuildResultDatablock(SOperatorInfo* pOperator, SOptrBasicInfo* pbInfo, SG
|
|||
pBlock->info.id.groupId = 0;
|
||||
if (!pbInfo->mergeResultBlock) {
|
||||
doCopyToSDataBlock(pTaskInfo, pBlock, &pOperator->exprSupp, pBuf, pGroupResInfo, pOperator->resultInfo.threshold,
|
||||
false);
|
||||
false, getMinWindowSize(pOperator));
|
||||
} else {
|
||||
while (hasRemainResults(pGroupResInfo)) {
|
||||
doCopyToSDataBlock(pTaskInfo, pBlock, &pOperator->exprSupp, pBuf, pGroupResInfo, pOperator->resultInfo.threshold,
|
||||
true);
|
||||
true, getMinWindowSize(pOperator));
|
||||
if (pBlock->info.rows >= pOperator->resultInfo.threshold) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -395,7 +395,7 @@ static int32_t buildCountResult(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
|
|||
STaskNotifyEventStat* pNotifyEventStat = pTaskInfo->streamInfo.pNotifyEventStat;
|
||||
bool addNotifyEvent = false;
|
||||
addNotifyEvent = BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_CLOSE);
|
||||
doBuildDeleteDataBlock(pOperator, pInfo->pStDeleted, pInfo->pDelRes, &pInfo->pDelIterator);
|
||||
doBuildDeleteDataBlock(pOperator, pInfo->pStDeleted, pInfo->pDelRes, &pInfo->pDelIterator, &pInfo->groupResInfo);
|
||||
if (pInfo->pDelRes->info.rows > 0) {
|
||||
printDataBlock(pInfo->pDelRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
|
||||
if (addNotifyEvent) {
|
||||
|
|
|
@ -617,7 +617,7 @@ static int32_t buildEventResult(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
|
|||
STaskNotifyEventStat* pNotifyEventStat = pTaskInfo->streamInfo.pNotifyEventStat;
|
||||
bool addNotifyEvent = false;
|
||||
addNotifyEvent = BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_CLOSE);
|
||||
doBuildDeleteDataBlock(pOperator, pInfo->pSeDeleted, pInfo->pDelRes, &pInfo->pDelIterator);
|
||||
doBuildDeleteDataBlock(pOperator, pInfo->pSeDeleted, pInfo->pDelRes, &pInfo->pDelIterator, &pInfo->groupResInfo);
|
||||
if (pInfo->pDelRes->info.rows > 0) {
|
||||
printDataBlock(pInfo->pDelRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
|
||||
if (addNotifyEvent) {
|
||||
|
@ -1075,6 +1075,8 @@ int32_t createStreamEventAggOperatorInfo(SOperatorInfo* downstream, SPhysiNode*
|
|||
code = nodesCollectColumnsFromNode((SNode*)pEventNode->pEndCond, NULL, COLLECT_COL_TYPE_ALL, &pInfo->pEndCondCols);
|
||||
QUERY_CHECK_CODE(code, lino, _error);
|
||||
|
||||
pInfo->trueForLimit = pEventNode->trueForLimit;
|
||||
|
||||
*pOptrInfo = pOperator;
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
||||
|
|
|
@ -485,6 +485,7 @@ void clearGroupResInfo(SGroupResInfo* pGroupResInfo) {
|
|||
taosArrayDestroy(pGroupResInfo->pRows);
|
||||
pGroupResInfo->pRows = NULL;
|
||||
pGroupResInfo->index = 0;
|
||||
pGroupResInfo->delIndex = 0;
|
||||
}
|
||||
|
||||
void destroyStreamFinalIntervalOperatorInfo(void* param) {
|
||||
|
@ -2887,39 +2888,27 @@ inline int32_t sessionKeyCompareAsc(const void* pKey1, const void* pKey2) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void doBuildDeleteDataBlock(SOperatorInfo* pOp, SSHashObj* pStDeleted, SSDataBlock* pBlock, void** Ite) {
|
||||
static int32_t appendToDeleteDataBlock(SOperatorInfo* pOp, SSDataBlock *pBlock, SSessionKey *pKey) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
int32_t lino = 0;
|
||||
SStorageAPI* pAPI = &pOp->pTaskInfo->storageAPI;
|
||||
SExecTaskInfo* pTaskInfo = pOp->pTaskInfo;
|
||||
|
||||
blockDataCleanup(pBlock);
|
||||
int32_t size = tSimpleHashGetSize(pStDeleted);
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
code = blockDataEnsureCapacity(pBlock, size);
|
||||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
QUERY_CHECK_NULL(pBlock, code, lino, _end, TSDB_CODE_INVALID_PARA);
|
||||
QUERY_CHECK_NULL(pKey, code, lino, _end, TSDB_CODE_INVALID_PARA);
|
||||
|
||||
int32_t iter = 0;
|
||||
while (((*Ite) = tSimpleHashIterate(pStDeleted, *Ite, &iter)) != NULL) {
|
||||
if (pBlock->info.rows + 1 > pBlock->info.capacity) {
|
||||
break;
|
||||
}
|
||||
SSessionKey* res = tSimpleHashGetKey(*Ite, NULL);
|
||||
SColumnInfoData* pStartTsCol = taosArrayGet(pBlock->pDataBlock, START_TS_COLUMN_INDEX);
|
||||
code = colDataSetVal(pStartTsCol, pBlock->info.rows, (const char*)&res->win.skey, false);
|
||||
code = colDataSetVal(pStartTsCol, pBlock->info.rows, (const char*)&pKey->win.skey, false);
|
||||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
|
||||
SColumnInfoData* pEndTsCol = taosArrayGet(pBlock->pDataBlock, END_TS_COLUMN_INDEX);
|
||||
code = colDataSetVal(pEndTsCol, pBlock->info.rows, (const char*)&res->win.skey, false);
|
||||
code = colDataSetVal(pEndTsCol, pBlock->info.rows, (const char*)&pKey->win.skey, false);
|
||||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
|
||||
SColumnInfoData* pUidCol = taosArrayGet(pBlock->pDataBlock, UID_COLUMN_INDEX);
|
||||
colDataSetNULL(pUidCol, pBlock->info.rows);
|
||||
|
||||
SColumnInfoData* pGpCol = taosArrayGet(pBlock->pDataBlock, GROUPID_COLUMN_INDEX);
|
||||
code = colDataSetVal(pGpCol, pBlock->info.rows, (const char*)&res->groupId, false);
|
||||
code = colDataSetVal(pGpCol, pBlock->info.rows, (const char*)&pKey->groupId, false);
|
||||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
|
||||
SColumnInfoData* pCalStCol = taosArrayGet(pBlock->pDataBlock, CALCULATE_START_TS_COLUMN_INDEX);
|
||||
|
@ -2935,8 +2924,9 @@ void doBuildDeleteDataBlock(SOperatorInfo* pOp, SSHashObj* pStDeleted, SSDataBlo
|
|||
|
||||
void* tbname = NULL;
|
||||
int32_t winCode = TSDB_CODE_SUCCESS;
|
||||
code = pAPI->stateStore.streamStateGetParName(pOp->pTaskInfo->streamInfo.pState, res->groupId, &tbname, false,
|
||||
&winCode);
|
||||
SStorageAPI* pAPI = &pOp->pTaskInfo->storageAPI;
|
||||
code =
|
||||
pAPI->stateStore.streamStateGetParName(pOp->pTaskInfo->streamInfo.pState, pKey->groupId, &tbname, false, &winCode);
|
||||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
|
||||
if (winCode != TSDB_CODE_SUCCESS) {
|
||||
|
@ -2949,6 +2939,62 @@ void doBuildDeleteDataBlock(SOperatorInfo* pOp, SSHashObj* pStDeleted, SSDataBlo
|
|||
pAPI->stateStore.streamStateFreeVal(tbname);
|
||||
}
|
||||
pBlock->info.rows += 1;
|
||||
|
||||
_end:
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
void doBuildDeleteDataBlock(SOperatorInfo* pOp, SSHashObj* pStDeleted, SSDataBlock* pBlock, void** Ite,
|
||||
SGroupResInfo* pGroupResInfo) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
int32_t lino = 0;
|
||||
SExecTaskInfo* pTaskInfo = pOp->pTaskInfo;
|
||||
int64_t minWindowSize = getMinWindowSize(pOp);
|
||||
int32_t numOfRows = getNumOfTotalRes(pGroupResInfo);
|
||||
|
||||
blockDataCleanup(pBlock);
|
||||
int32_t size = tSimpleHashGetSize(pStDeleted);
|
||||
if (minWindowSize > 0) {
|
||||
// Add the number of windows that are below the minimum width limit.
|
||||
for (int32_t i = pGroupResInfo->delIndex; i < numOfRows; ++i) {
|
||||
SResultWindowInfo* pWinInfo = taosArrayGet(pGroupResInfo->pRows, i);
|
||||
SRowBuffPos* pPos = pWinInfo->pStatePos;
|
||||
SSessionKey* pKey = (SSessionKey*)pPos->pKey;
|
||||
if (pKey->win.ekey - pKey->win.skey < minWindowSize) {
|
||||
size++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
code = blockDataEnsureCapacity(pBlock, size);
|
||||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
|
||||
int32_t iter = 0;
|
||||
while (((*Ite) = tSimpleHashIterate(pStDeleted, *Ite, &iter)) != NULL) {
|
||||
if (pBlock->info.rows + 1 > pBlock->info.capacity) {
|
||||
break;
|
||||
}
|
||||
SSessionKey* res = tSimpleHashGetKey(*Ite, NULL);
|
||||
code = appendToDeleteDataBlock(pOp, pBlock, res);
|
||||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
}
|
||||
|
||||
if (minWindowSize > 0) {
|
||||
for (int32_t i = pGroupResInfo->delIndex; i < numOfRows; ++i) {
|
||||
SResultWindowInfo* pWinInfo = taosArrayGet(pGroupResInfo->pRows, i);
|
||||
SRowBuffPos* pPos = pWinInfo->pStatePos;
|
||||
SSessionKey* pKey = (SSessionKey*)pPos->pKey;
|
||||
if (pKey->win.ekey - pKey->win.skey < minWindowSize) {
|
||||
code = appendToDeleteDataBlock(pOp, pBlock, pKey);
|
||||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
}
|
||||
}
|
||||
pGroupResInfo->delIndex = numOfRows;
|
||||
}
|
||||
|
||||
_end:
|
||||
|
@ -3141,6 +3187,7 @@ void initGroupResInfoFromArrayList(SGroupResInfo* pGroupResInfo, SArray* pArrayL
|
|||
pGroupResInfo->index = 0;
|
||||
pGroupResInfo->pBuf = NULL;
|
||||
pGroupResInfo->freeItem = false;
|
||||
pGroupResInfo->delIndex = 0;
|
||||
}
|
||||
|
||||
int32_t buildSessionResultDataBlock(SOperatorInfo* pOperator, void* pState, SSDataBlock* pBlock, SExprSupp* pSup,
|
||||
|
@ -3153,6 +3200,7 @@ int32_t buildSessionResultDataBlock(SOperatorInfo* pOperator, void* pState, SSDa
|
|||
int32_t numOfExprs = pSup->numOfExprs;
|
||||
int32_t* rowEntryOffset = pSup->rowEntryInfoOffset;
|
||||
SqlFunctionCtx* pCtx = pSup->pCtx;
|
||||
int64_t minWindowSize = getMinWindowSize(pOperator);
|
||||
|
||||
int32_t numOfRows = getNumOfTotalRes(pGroupResInfo);
|
||||
|
||||
|
@ -3193,6 +3241,13 @@ int32_t buildSessionResultDataBlock(SOperatorInfo* pOperator, void* pState, SSDa
|
|||
pGroupResInfo->index += 1;
|
||||
continue;
|
||||
}
|
||||
// skip the window which is less than the windowMinSize
|
||||
if (pKey->win.ekey - pKey->win.skey < minWindowSize) {
|
||||
qDebug("skip small window, groupId: %" PRId64 ", windowSize: %" PRId64 ", minWindowSize: %" PRId64, pKey->groupId,
|
||||
pKey->win.ekey - pKey->win.skey, minWindowSize);
|
||||
pGroupResInfo->index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pBlock->info.rows + pRow->numOfRows > pBlock->info.capacity) {
|
||||
break;
|
||||
|
@ -3286,7 +3341,7 @@ static int32_t buildSessionResult(SOperatorInfo* pOperator, SSDataBlock** ppRes)
|
|||
bool addNotifyEvent = false;
|
||||
addNotifyEvent = IS_NORMAL_SESSION_OP(pOperator) &&
|
||||
BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_CLOSE);
|
||||
doBuildDeleteDataBlock(pOperator, pInfo->pStDeleted, pInfo->pDelRes, &pInfo->pDelIterator);
|
||||
doBuildDeleteDataBlock(pOperator, pInfo->pStDeleted, pInfo->pDelRes, &pInfo->pDelIterator, &pInfo->groupResInfo);
|
||||
if (pInfo->pDelRes->info.rows > 0) {
|
||||
printDataBlock(pInfo->pDelRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
|
||||
if (addNotifyEvent) {
|
||||
|
@ -4928,7 +4983,7 @@ static int32_t buildStateResult(SOperatorInfo* pOperator, SSDataBlock** ppRes) {
|
|||
STaskNotifyEventStat* pNotifyEventStat = pTaskInfo->streamInfo.pNotifyEventStat;
|
||||
bool addNotifyEvent = false;
|
||||
addNotifyEvent = BIT_FLAG_TEST_MASK(pTaskInfo->streamInfo.eventTypes, SNOTIFY_EVENT_WINDOW_CLOSE);
|
||||
doBuildDeleteDataBlock(pOperator, pInfo->pSeDeleted, pInfo->pDelRes, &pInfo->pDelIterator);
|
||||
doBuildDeleteDataBlock(pOperator, pInfo->pSeDeleted, pInfo->pDelRes, &pInfo->pDelIterator, &pInfo->groupResInfo);
|
||||
if (pInfo->pDelRes->info.rows > 0) {
|
||||
printDataBlock(pInfo->pDelRes, getStreamOpName(pOperator->operatorType), GET_TASKID(pTaskInfo));
|
||||
if (addNotifyEvent) {
|
||||
|
@ -5363,6 +5418,8 @@ int32_t createStreamStateAggOperatorInfo(SOperatorInfo* downstream, SPhysiNode*
|
|||
code = appendDownstream(pOperator, &downstream, 1);
|
||||
QUERY_CHECK_CODE(code, lino, _error);
|
||||
|
||||
pInfo->trueForLimit = pStateNode->trueForLimit;
|
||||
|
||||
*pOptrInfo = pOperator;
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
||||
|
|
|
@ -1390,3 +1390,22 @@ void destroyTimeSliceOperatorInfo(void* param) {
|
|||
}
|
||||
taosMemoryFreeClear(param);
|
||||
}
|
||||
|
||||
int64_t getMinWindowSize(struct SOperatorInfo* pOperator) {
|
||||
if (pOperator == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (pOperator->operatorType) {
|
||||
case QUERY_NODE_PHYSICAL_PLAN_MERGE_STATE:
|
||||
return ((SStateWindowOperatorInfo*)pOperator->info)->trueForLimit;
|
||||
case QUERY_NODE_PHYSICAL_PLAN_STREAM_STATE:
|
||||
return ((SStreamStateAggOperatorInfo*)pOperator->info)->trueForLimit;
|
||||
case QUERY_NODE_PHYSICAL_PLAN_MERGE_EVENT:
|
||||
return ((SEventWindowOperatorInfo*)pOperator->info)->trueForLimit;
|
||||
case QUERY_NODE_PHYSICAL_PLAN_STREAM_EVENT:
|
||||
return ((SStreamEventAggOperatorInfo*)pOperator->info)->trueForLimit;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,35 +27,6 @@
|
|||
#include "tlog.h"
|
||||
#include "ttime.h"
|
||||
|
||||
typedef struct SSessionAggOperatorInfo {
|
||||
SOptrBasicInfo binfo;
|
||||
SAggSupporter aggSup;
|
||||
SExprSupp scalarSupp; // supporter for perform scalar function
|
||||
SGroupResInfo groupResInfo;
|
||||
SWindowRowsSup winSup;
|
||||
bool reptScan; // next round scan
|
||||
int64_t gap; // session window gap
|
||||
int32_t tsSlotId; // primary timestamp slot id
|
||||
STimeWindowAggSupp twAggSup;
|
||||
SOperatorInfo* pOperator;
|
||||
bool cleanGroupResInfo;
|
||||
} SSessionAggOperatorInfo;
|
||||
|
||||
typedef struct SStateWindowOperatorInfo {
|
||||
SOptrBasicInfo binfo;
|
||||
SAggSupporter aggSup;
|
||||
SExprSupp scalarSup;
|
||||
SGroupResInfo groupResInfo;
|
||||
SWindowRowsSup winSup;
|
||||
SColumn stateCol; // start row index
|
||||
bool hasKey;
|
||||
SStateKeys stateKey;
|
||||
int32_t tsSlotId; // primary timestamp column slot id
|
||||
STimeWindowAggSupp twAggSup;
|
||||
SOperatorInfo* pOperator;
|
||||
bool cleanGroupResInfo;
|
||||
} SStateWindowOperatorInfo;
|
||||
|
||||
typedef enum SResultTsInterpType {
|
||||
RESULT_ROW_START_INTERP = 1,
|
||||
RESULT_ROW_END_INTERP = 2,
|
||||
|
@ -1743,6 +1714,7 @@ int32_t createStatewindowOperatorInfo(SOperatorInfo* downstream, SStateWinodwPhy
|
|||
pInfo->tsSlotId = tsSlotId;
|
||||
pInfo->pOperator = pOperator;
|
||||
pInfo->cleanGroupResInfo = false;
|
||||
pInfo->trueForLimit = pStateNode->trueForLimit;
|
||||
setOperatorInfo(pOperator, "StateWindowOperator", QUERY_NODE_PHYSICAL_PLAN_MERGE_STATE, true, OP_NOT_OPENED, pInfo,
|
||||
pTaskInfo);
|
||||
pOperator->fpSet = createOperatorFpSet(openStateWindowAggOptr, doStateWindowAggNext, NULL, destroyStateWindowOperatorInfo,
|
||||
|
|
|
@ -59,6 +59,7 @@ extern "C" {
|
|||
#define FUNC_MGT_COUNT_LIKE_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(30) // funcs that should also return 0 when no rows found
|
||||
#define FUNC_MGT_PROCESS_BY_ROW FUNC_MGT_FUNC_CLASSIFICATION_MASK(31)
|
||||
#define FUNC_MGT_FORECAST_PC_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(32)
|
||||
#define FUNC_MGT_SELECT_COLS_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(33)
|
||||
|
||||
#define FUNC_MGT_TEST_MASK(val, mask) (((val) & (mask)) != 0)
|
||||
|
||||
|
|
|
@ -1702,6 +1702,10 @@ static int32_t translateOutVarchar(SFunctionNode* pFunc, char* pErrBuf, int32_t
|
|||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t invalidColsFunction(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
|
||||
return TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||
}
|
||||
|
||||
static int32_t translateHistogramImpl(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
|
||||
FUNC_ERR_RET(validateParam(pFunc, pErrBuf, len));
|
||||
int32_t numOfParams = LIST_LENGTH(pFunc->pParameterList);
|
||||
|
@ -2737,7 +2741,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
|||
.translateFunc = translateOutFirstIn,
|
||||
.dynDataRequiredFunc = firstDynDataReq,
|
||||
.getEnvFunc = getFirstLastFuncEnv,
|
||||
.initFunc = functionSetup,
|
||||
.initFunc = firstLastFunctionSetup,
|
||||
.processFunc = firstFunction,
|
||||
.sprocessFunc = firstLastScalarFunction,
|
||||
.finalizeFunc = firstLastFinalize,
|
||||
|
@ -4232,7 +4236,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
|||
{
|
||||
.name = "_group_key",
|
||||
.type = FUNCTION_TYPE_GROUP_KEY,
|
||||
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_KEEP_ORDER_FUNC | FUNC_MGT_SKIP_SCAN_CHECK_FUNC,
|
||||
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_KEEP_ORDER_FUNC | FUNC_MGT_SKIP_SCAN_CHECK_FUNC,
|
||||
.translateFunc = translateGroupKey,
|
||||
.getEnvFunc = getGroupKeyFuncEnv,
|
||||
.initFunc = functionSetup,
|
||||
|
@ -4952,7 +4956,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
|||
{
|
||||
.name = "_group_const_value",
|
||||
.type = FUNCTION_TYPE_GROUP_CONST_VALUE,
|
||||
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_KEEP_ORDER_FUNC,
|
||||
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_KEEP_ORDER_FUNC,
|
||||
.parameters = {.minParamNum = 0,
|
||||
.maxParamNum = 0,
|
||||
.paramInfoPattern = 0,
|
||||
|
@ -5647,7 +5651,11 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
|||
.paramInfoPattern = 0,
|
||||
.outputParaInfo = {.validDataType = FUNC_PARAM_SUPPORT_VARCHAR_TYPE}},
|
||||
.translateFunc = translateOutVarchar,
|
||||
}
|
||||
},
|
||||
{
|
||||
.name = "cols",
|
||||
.translateFunc = invalidColsFunction,
|
||||
},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
|
|
@ -912,14 +912,13 @@ int32_t minmaxFunctionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
|
|||
if (pEntryInfo->numOfRes > 0) {
|
||||
code = setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
|
||||
} else {
|
||||
code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
|
||||
code = setNullSelectivityValue(pCtx, pBlock, currentRow);
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
#ifdef BUILD_NO_CALL
|
||||
int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t rowIndex) {
|
||||
if (pCtx->subsidiaries.num <= 0) {
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
@ -930,12 +929,14 @@ int32_t setNullSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, int32
|
|||
int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
|
||||
|
||||
SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
|
||||
if (NULL == pDstCol) {
|
||||
return terrno;
|
||||
}
|
||||
colDataSetNULL(pDstCol, rowIndex);
|
||||
}
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STuplePos* pTuplePos, int32_t rowIndex) {
|
||||
if (pCtx->subsidiaries.num <= 0) {
|
||||
|
@ -961,20 +962,14 @@ int32_t setSelectivityValue(SqlFunctionCtx* pCtx, SSDataBlock* pBlock, const STu
|
|||
SqlFunctionCtx* pc = pCtx->subsidiaries.pCtx[j];
|
||||
int32_t dstSlotId = pc->pExpr->base.resSchema.slotId;
|
||||
|
||||
// group_key function has its own process function
|
||||
// do not process there
|
||||
if (fmIsGroupKeyFunc(pc->functionId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SColumnInfoData* pDstCol = taosArrayGet(pBlock->pDataBlock, dstSlotId);
|
||||
if (NULL == pDstCol) {
|
||||
return TSDB_CODE_OUT_OF_RANGE;
|
||||
return terrno;
|
||||
}
|
||||
if (nullList[j]) {
|
||||
colDataSetNULL(pDstCol, rowIndex);
|
||||
} else {
|
||||
code = colDataSetVal(pDstCol, rowIndex, pStart, false);
|
||||
code = colDataSetValOrCover(pDstCol, rowIndex, pStart, false);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
return code;
|
||||
}
|
||||
|
@ -2431,8 +2426,6 @@ int32_t firstLastFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResIn
|
|||
}
|
||||
|
||||
SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pResInfo);
|
||||
SInputColumnInfoData* pInput = &pCtx->input;
|
||||
|
||||
pRes->nullTupleSaved = false;
|
||||
pRes->nullTuplePos.pageId = -1;
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
@ -2464,10 +2457,10 @@ static int32_t firstlastSaveTupleData(const SSDataBlock* pSrcBlock, int32_t rowI
|
|||
}
|
||||
|
||||
if (!pInfo->hasResult) {
|
||||
code = saveTupleData(pCtx, rowIndex, pSrcBlock, noElements ? &pInfo->nullTuplePos : &pInfo->pos);
|
||||
} else {
|
||||
code = saveTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
|
||||
} else if (!noElements) {
|
||||
code = updateTupleData(pCtx, rowIndex, pSrcBlock, &pInfo->pos);
|
||||
}
|
||||
} else { } // dothing
|
||||
|
||||
return code;
|
||||
}
|
||||
|
@ -2538,7 +2531,7 @@ int32_t firstFunction(SqlFunctionCtx* pCtx) {
|
|||
if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
|
||||
pInputCol->hasNull == true) {
|
||||
// save selectivity value for column consisted of all null values
|
||||
int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, !pInfo->nullTupleSaved);
|
||||
int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
@ -2633,7 +2626,7 @@ int32_t firstFunction(SqlFunctionCtx* pCtx) {
|
|||
|
||||
if (numOfElems == 0) {
|
||||
// save selectivity value for column consisted of all null values
|
||||
int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, !pInfo->nullTupleSaved);
|
||||
int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
@ -2654,11 +2647,11 @@ int32_t lastFunction(SqlFunctionCtx* pCtx) {
|
|||
|
||||
int32_t type = pInputCol->info.type;
|
||||
int32_t bytes = pInputCol->info.bytes;
|
||||
pInfo->bytes = bytes;
|
||||
|
||||
if (IS_NULL_TYPE(type)) {
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
pInfo->bytes = bytes;
|
||||
|
||||
SColumnInfoData* pkCol = pInput->pPrimaryKey;
|
||||
pInfo->pkType = -1;
|
||||
|
@ -2673,7 +2666,7 @@ int32_t lastFunction(SqlFunctionCtx* pCtx) {
|
|||
if (pInput->colDataSMAIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows) &&
|
||||
pInputCol->hasNull == true) {
|
||||
// save selectivity value for column consisted of all null values
|
||||
int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, !pInfo->nullTupleSaved);
|
||||
int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
@ -2768,7 +2761,7 @@ int32_t lastFunction(SqlFunctionCtx* pCtx) {
|
|||
|
||||
if (pResInfo->numOfRes == 0 || pInfo->ts < cts) {
|
||||
char* data = colDataGetData(pInputCol, chosen);
|
||||
int32_t code = doSaveCurrentVal(pCtx, i, cts, NULL, type, data);
|
||||
int32_t code = doSaveCurrentVal(pCtx, chosen, cts, NULL, type, data);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
@ -2816,7 +2809,7 @@ int32_t lastFunction(SqlFunctionCtx* pCtx) {
|
|||
|
||||
// save selectivity value for column consisted of all null values
|
||||
if (numOfElems == 0) {
|
||||
int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, !pInfo->nullTupleSaved);
|
||||
int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
@ -2865,7 +2858,7 @@ static bool firstLastTransferInfoImpl(SFirstLastRes* pInput, SFirstLastRes* pOut
|
|||
static int32_t firstLastTransferInfo(SqlFunctionCtx* pCtx, SFirstLastRes* pInput, SFirstLastRes* pOutput, bool isFirst,
|
||||
int32_t rowIndex) {
|
||||
if (firstLastTransferInfoImpl(pInput, pOutput, isFirst)) {
|
||||
int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pOutput, pOutput->nullTupleSaved);
|
||||
int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, rowIndex, pCtx, pOutput, false);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
return code;
|
||||
}
|
||||
|
@ -2914,7 +2907,7 @@ static int32_t firstLastFunctionMergeImpl(SqlFunctionCtx* pCtx, bool isFirstQuer
|
|||
}
|
||||
|
||||
if (numOfElems == 0) {
|
||||
int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, !pInfo->nullTupleSaved);
|
||||
int32_t code = firstlastSaveTupleData(pCtx->pSrcBlock, pInput->startRowIndex, pCtx, pInfo, true);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
@ -2944,7 +2937,7 @@ int32_t firstLastFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
|
|||
|
||||
if (pResInfo->isNullRes) {
|
||||
colDataSetNULL(pCol, pBlock->info.rows);
|
||||
return setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, pBlock->info.rows);
|
||||
return setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
|
||||
}
|
||||
code = colDataSetVal(pCol, pBlock->info.rows, pRes->buf, pRes->isNull || pResInfo->isNullRes);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
|
@ -2983,7 +2976,7 @@ int32_t firstLastPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
|
|||
|
||||
if (pEntryInfo->numOfRes == 0) {
|
||||
colDataSetNULL(pCol, pBlock->info.rows);
|
||||
code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, pBlock->info.rows);
|
||||
code = setNullSelectivityValue(pCtx, pBlock, pBlock->info.rows);
|
||||
} else {
|
||||
code = colDataSetVal(pCol, pBlock->info.rows, res, false);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
|
|
|
@ -173,6 +173,8 @@ bool fmIsScalarFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC
|
|||
|
||||
bool fmIsVectorFunc(int32_t funcId) { return !fmIsScalarFunc(funcId) && !fmIsPseudoColumnFunc(funcId); }
|
||||
|
||||
bool fmIsSelectColsFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MGT_SELECT_COLS_FUNC); }
|
||||
|
||||
bool fmIsSelectFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MGT_SELECT_FUNC); }
|
||||
|
||||
bool fmIsTimelineFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MGT_TIMELINE_FUNC); }
|
||||
|
@ -441,6 +443,8 @@ int32_t createFunctionWithSrcFunc(const char* pName, const SFunctionNode* pSrcFu
|
|||
return code;
|
||||
}
|
||||
resetOutputChangedFunc(*ppFunc, pSrcFunc);
|
||||
(*ppFunc)->node.relatedTo = pSrcFunc->node.relatedTo;
|
||||
(*ppFunc)->node.bindExprID = pSrcFunc->node.bindExprID;
|
||||
return code;
|
||||
}
|
||||
|
||||
|
|
|
@ -106,6 +106,8 @@ static int32_t exprNodeCopy(const SExprNode* pSrc, SExprNode* pDst) {
|
|||
COPY_SCALAR_FIELD(asParam);
|
||||
COPY_SCALAR_FIELD(asPosition);
|
||||
COPY_SCALAR_FIELD(projIdx);
|
||||
COPY_SCALAR_FIELD(relatedTo);
|
||||
COPY_SCALAR_FIELD(bindExprID);
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -354,6 +356,7 @@ static int32_t limitNodeCopy(const SLimitNode* pSrc, SLimitNode* pDst) {
|
|||
static int32_t stateWindowNodeCopy(const SStateWindowNode* pSrc, SStateWindowNode* pDst) {
|
||||
CLONE_NODE_FIELD(pCol);
|
||||
CLONE_NODE_FIELD(pExpr);
|
||||
CLONE_NODE_FIELD(pTrueForLimit);
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -361,6 +364,7 @@ static int32_t eventWindowNodeCopy(const SEventWindowNode* pSrc, SEventWindowNod
|
|||
CLONE_NODE_FIELD(pCol);
|
||||
CLONE_NODE_FIELD(pStartCond);
|
||||
CLONE_NODE_FIELD(pEndCond);
|
||||
CLONE_NODE_FIELD(pTrueForLimit);
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -627,6 +631,7 @@ static int32_t logicWindowCopy(const SWindowLogicNode* pSrc, SWindowLogicNode* p
|
|||
CLONE_NODE_FIELD(pStateExpr);
|
||||
CLONE_NODE_FIELD(pStartCond);
|
||||
CLONE_NODE_FIELD(pEndCond);
|
||||
COPY_SCALAR_FIELD(trueForLimit);
|
||||
COPY_SCALAR_FIELD(triggerType);
|
||||
COPY_SCALAR_FIELD(watermark);
|
||||
COPY_SCALAR_FIELD(deleteMark);
|
||||
|
|
|
@ -3127,6 +3127,7 @@ static int32_t jsonToPhysiSessionWindowNode(const SJson* pJson, void* pObj) {
|
|||
}
|
||||
|
||||
static const char* jkStateWindowPhysiPlanStateKey = "StateKey";
|
||||
static const char* jkStateWindowPhysiPlanTrueForLimit = "TrueForLimit";
|
||||
|
||||
static int32_t physiStateWindowNodeToJson(const void* pObj, SJson* pJson) {
|
||||
const SStateWinodwPhysiNode* pNode = (const SStateWinodwPhysiNode*)pObj;
|
||||
|
@ -3135,6 +3136,9 @@ static int32_t physiStateWindowNodeToJson(const void* pObj, SJson* pJson) {
|
|||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddObject(pJson, jkStateWindowPhysiPlanStateKey, nodeToJson, pNode->pStateKey);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkStateWindowPhysiPlanTrueForLimit, pNode->trueForLimit);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
@ -3146,12 +3150,16 @@ static int32_t jsonToPhysiStateWindowNode(const SJson* pJson, void* pObj) {
|
|||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = jsonToNodeObject(pJson, jkStateWindowPhysiPlanStateKey, &pNode->pStateKey);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetBigIntValue(pJson, jkStateWindowPhysiPlanTrueForLimit, &pNode->trueForLimit);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static const char* jkEventWindowPhysiPlanStartCond = "StartCond";
|
||||
static const char* jkEventWindowPhysiPlanEndCond = "EndCond";
|
||||
static const char* jkEventWindowPhysiPlanTrueForLimit = "TrueForLimit";
|
||||
|
||||
static int32_t physiEventWindowNodeToJson(const void* pObj, SJson* pJson) {
|
||||
const SEventWinodwPhysiNode* pNode = (const SEventWinodwPhysiNode*)pObj;
|
||||
|
@ -3163,6 +3171,9 @@ static int32_t physiEventWindowNodeToJson(const void* pObj, SJson* pJson) {
|
|||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddObject(pJson, jkEventWindowPhysiPlanEndCond, nodeToJson, pNode->pEndCond);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkEventWindowPhysiPlanTrueForLimit, pNode->trueForLimit);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
@ -3177,6 +3188,9 @@ static int32_t jsonToPhysiEventWindowNode(const SJson* pJson, void* pObj) {
|
|||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = jsonToNodeObject(pJson, jkEventWindowPhysiPlanEndCond, &pNode->pEndCond);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetBigIntValue(pJson, jkEventWindowPhysiPlanTrueForLimit, &pNode->trueForLimit);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
@ -4960,6 +4974,7 @@ static int32_t jsonToLimitNode(const SJson* pJson, void* pObj) {
|
|||
|
||||
static const char* jkStateWindowCol = "StateWindowCol";
|
||||
static const char* jkStateWindowExpr = "StateWindowExpr";
|
||||
static const char* jkStateWindowTrueForLimit = "TrueForLimit";
|
||||
|
||||
static int32_t stateWindowNodeToJson(const void* pObj, SJson* pJson) {
|
||||
const SStateWindowNode* pNode = (const SStateWindowNode*)pObj;
|
||||
|
@ -4967,6 +4982,9 @@ static int32_t stateWindowNodeToJson(const void* pObj, SJson* pJson) {
|
|||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddObject(pJson, jkStateWindowExpr, nodeToJson, pNode->pExpr);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddObject(pJson, jkStateWindowTrueForLimit, nodeToJson, pNode->pTrueForLimit);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -4977,6 +4995,9 @@ static int32_t jsonToStateWindowNode(const SJson* pJson, void* pObj) {
|
|||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = jsonToNodeObject(pJson, jkStateWindowExpr, (SNode**)&pNode->pExpr);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = jsonToNodeObject(pJson, jkStateWindowTrueForLimit, (SNode**)&pNode->pTrueForLimit);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -5006,6 +5027,7 @@ static int32_t jsonToSessionWindowNode(const SJson* pJson, void* pObj) {
|
|||
static const char* jkEventWindowTsPrimaryKey = "TsPrimaryKey";
|
||||
static const char* jkEventWindowStartCond = "StartCond";
|
||||
static const char* jkEventWindowEndCond = "EndCond";
|
||||
static const char* jkEventWindowTrueForLimit = "TrueForLimit";
|
||||
|
||||
static int32_t eventWindowNodeToJson(const void* pObj, SJson* pJson) {
|
||||
const SEventWindowNode* pNode = (const SEventWindowNode*)pObj;
|
||||
|
@ -5017,6 +5039,9 @@ static int32_t eventWindowNodeToJson(const void* pObj, SJson* pJson) {
|
|||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddObject(pJson, jkEventWindowEndCond, nodeToJson, pNode->pEndCond);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddObject(pJson, jkEventWindowTrueForLimit, nodeToJson, pNode->pTrueForLimit);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -5030,6 +5055,9 @@ static int32_t jsonToEventWindowNode(const SJson* pJson, void* pObj) {
|
|||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = jsonToNodeObject(pJson, jkEventWindowEndCond, &pNode->pEndCond);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = jsonToNodeObject(pJson, jkEventWindowTrueForLimit, &pNode->pTrueForLimit);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "functionMgt.h"
|
||||
#include "querynodes.h"
|
||||
|
||||
#define COMPARE_SCALAR_FIELD(fldname) \
|
||||
|
@ -137,6 +138,15 @@ static bool functionNodeEqual(const SFunctionNode* a, const SFunctionNode* b) {
|
|||
COMPARE_SCALAR_FIELD(funcId);
|
||||
COMPARE_STRING_FIELD(functionName);
|
||||
COMPARE_NODE_LIST_FIELD(pParameterList);
|
||||
if (a->funcType == FUNCTION_TYPE_SELECT_VALUE) {
|
||||
if ((a->node.relatedTo != b->node.relatedTo)) return false;
|
||||
} else {
|
||||
// select cols(cols(first(c0), ts), first(c0) from meters;
|
||||
if ((a->node.bindExprID != b->node.bindExprID)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -664,11 +664,18 @@ static int32_t msgToDataType(STlvDecoder* pDecoder, void* pObj) {
|
|||
return code;
|
||||
}
|
||||
|
||||
enum { EXPR_CODE_RES_TYPE = 1 };
|
||||
enum { EXPR_CODE_RES_TYPE = 1, EXPR_CODE_BIND_TUPLE_FUNC_IDX, EXPR_CODE_TUPLE_FUNC_IDX };
|
||||
|
||||
static int32_t exprNodeToMsg(const void* pObj, STlvEncoder* pEncoder) {
|
||||
const SExprNode* pNode = (const SExprNode*)pObj;
|
||||
return tlvEncodeObj(pEncoder, EXPR_CODE_RES_TYPE, dataTypeToMsg, &pNode->resType);
|
||||
int32_t code = tlvEncodeObj(pEncoder, EXPR_CODE_RES_TYPE, dataTypeToMsg, &pNode->resType);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tlvEncodeI32(pEncoder, EXPR_CODE_BIND_TUPLE_FUNC_IDX, pNode->relatedTo);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tlvEncodeI32(pEncoder, EXPR_CODE_TUPLE_FUNC_IDX, pNode->bindExprID);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t msgToExprNode(STlvDecoder* pDecoder, void* pObj) {
|
||||
|
@ -681,6 +688,12 @@ static int32_t msgToExprNode(STlvDecoder* pDecoder, void* pObj) {
|
|||
case EXPR_CODE_RES_TYPE:
|
||||
code = tlvDecodeObjFromTlv(pTlv, msgToDataType, &pNode->resType);
|
||||
break;
|
||||
case EXPR_CODE_BIND_TUPLE_FUNC_IDX:
|
||||
code = tlvDecodeI32(pTlv, &pNode->relatedTo);
|
||||
break;
|
||||
case EXPR_CODE_TUPLE_FUNC_IDX:
|
||||
code = tlvDecodeI32(pTlv, &pNode->bindExprID);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -695,6 +708,12 @@ static int32_t columnNodeInlineToMsg(const void* pObj, STlvEncoder* pEncoder) {
|
|||
const SColumnNode* pNode = (const SColumnNode*)pObj;
|
||||
|
||||
int32_t code = dataTypeInlineToMsg(&pNode->node.resType, pEncoder);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tlvEncodeValueI32(pEncoder, pNode->node.relatedTo);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tlvEncodeValueI32(pEncoder, pNode->node.bindExprID);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tlvEncodeValueU64(pEncoder, pNode->tableId);
|
||||
}
|
||||
|
@ -745,6 +764,12 @@ static int32_t msgToColumnNodeInline(STlvDecoder* pDecoder, void* pObj) {
|
|||
SColumnNode* pNode = (SColumnNode*)pObj;
|
||||
|
||||
int32_t code = msgToDataTypeInline(pDecoder, &pNode->node.resType);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tlvDecodeValueI32(pDecoder, &pNode->node.relatedTo);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tlvDecodeValueI32(pDecoder, &pNode->node.bindExprID);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tlvDecodeValueU64(pDecoder, &pNode->tableId);
|
||||
}
|
||||
|
@ -3443,7 +3468,7 @@ static int32_t msgToPhysiSessionWindowNode(STlvDecoder* pDecoder, void* pObj) {
|
|||
return code;
|
||||
}
|
||||
|
||||
enum { PHY_STATE_CODE_WINDOW = 1, PHY_STATE_CODE_KEY };
|
||||
enum { PHY_STATE_CODE_WINDOW = 1, PHY_STATE_CODE_KEY, PHY_STATE_CODE_TRUE_FOR_LIMIT };
|
||||
|
||||
static int32_t physiStateWindowNodeToMsg(const void* pObj, STlvEncoder* pEncoder) {
|
||||
const SStateWinodwPhysiNode* pNode = (const SStateWinodwPhysiNode*)pObj;
|
||||
|
@ -3452,6 +3477,9 @@ static int32_t physiStateWindowNodeToMsg(const void* pObj, STlvEncoder* pEncoder
|
|||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tlvEncodeObj(pEncoder, PHY_STATE_CODE_KEY, nodeToMsg, pNode->pStateKey);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tlvEncodeI64(pEncoder, PHY_STATE_CODE_TRUE_FOR_LIMIT, pNode->trueForLimit);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
@ -3469,6 +3497,9 @@ static int32_t msgToPhysiStateWindowNode(STlvDecoder* pDecoder, void* pObj) {
|
|||
case PHY_STATE_CODE_KEY:
|
||||
code = msgToNodeFromTlv(pTlv, (void**)&pNode->pStateKey);
|
||||
break;
|
||||
case PHY_STATE_CODE_TRUE_FOR_LIMIT:
|
||||
code = tlvDecodeI64(pTlv, &pNode->trueForLimit);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -3477,7 +3508,7 @@ static int32_t msgToPhysiStateWindowNode(STlvDecoder* pDecoder, void* pObj) {
|
|||
return code;
|
||||
}
|
||||
|
||||
enum { PHY_EVENT_CODE_WINDOW = 1, PHY_EVENT_CODE_START_COND, PHY_EVENT_CODE_END_COND };
|
||||
enum { PHY_EVENT_CODE_WINDOW = 1, PHY_EVENT_CODE_START_COND, PHY_EVENT_CODE_END_COND, PHY_EVENT_CODE_TRUE_FOR_LIMIT };
|
||||
|
||||
static int32_t physiEventWindowNodeToMsg(const void* pObj, STlvEncoder* pEncoder) {
|
||||
const SEventWinodwPhysiNode* pNode = (const SEventWinodwPhysiNode*)pObj;
|
||||
|
@ -3489,6 +3520,9 @@ static int32_t physiEventWindowNodeToMsg(const void* pObj, STlvEncoder* pEncoder
|
|||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tlvEncodeObj(pEncoder, PHY_EVENT_CODE_END_COND, nodeToMsg, pNode->pEndCond);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tlvEncodeI64(pEncoder, PHY_EVENT_CODE_TRUE_FOR_LIMIT, pNode->trueForLimit);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
@ -3509,6 +3543,9 @@ static int32_t msgToPhysiEventWindowNode(STlvDecoder* pDecoder, void* pObj) {
|
|||
case PHY_EVENT_CODE_END_COND:
|
||||
code = msgToNodeFromTlv(pTlv, (void**)&pNode->pEndCond);
|
||||
break;
|
||||
case PHY_EVENT_CODE_TRUE_FOR_LIMIT:
|
||||
code = tlvDecodeI64(pTlv, &pNode->trueForLimit);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -102,6 +102,9 @@ static EDealRes dispatchExpr(SNode* pNode, ETraversalOrder order, FNodeWalker wa
|
|||
if (DEAL_RES_ERROR != res && DEAL_RES_END != res) {
|
||||
res = walkExpr(pState->pCol, order, walker, pContext);
|
||||
}
|
||||
if (DEAL_RES_ERROR != res && DEAL_RES_END != res) {
|
||||
res = walkExpr(pState->pTrueForLimit, order, walker, pContext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_SESSION_WINDOW: {
|
||||
|
@ -174,6 +177,9 @@ static EDealRes dispatchExpr(SNode* pNode, ETraversalOrder order, FNodeWalker wa
|
|||
if (DEAL_RES_ERROR != res && DEAL_RES_END != res) {
|
||||
res = walkExpr(pEvent->pEndCond, order, walker, pContext);
|
||||
}
|
||||
if (DEAL_RES_ERROR != res && DEAL_RES_END != res) {
|
||||
res = walkExpr(pEvent->pTrueForLimit, order, walker, pContext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_COUNT_WINDOW: {
|
||||
|
@ -313,6 +319,9 @@ static EDealRes rewriteExpr(SNode** pRawNode, ETraversalOrder order, FNodeRewrit
|
|||
if (DEAL_RES_ERROR != res && DEAL_RES_END != res) {
|
||||
res = rewriteExpr(&pState->pCol, order, rewriter, pContext);
|
||||
}
|
||||
if (DEAL_RES_ERROR != res && DEAL_RES_END != res) {
|
||||
res = rewriteExpr(&pState->pTrueForLimit, order, rewriter, pContext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_SESSION_WINDOW: {
|
||||
|
@ -385,6 +394,9 @@ static EDealRes rewriteExpr(SNode** pRawNode, ETraversalOrder order, FNodeRewrit
|
|||
if (DEAL_RES_ERROR != res && DEAL_RES_END != res) {
|
||||
res = rewriteExpr(&pEvent->pEndCond, order, rewriter, pContext);
|
||||
}
|
||||
if (DEAL_RES_ERROR != res && DEAL_RES_END != res) {
|
||||
res = rewriteExpr(&pEvent->pTrueForLimit, order, rewriter, pContext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_WINDOW_OFFSET: {
|
||||
|
@ -475,6 +487,7 @@ void nodesWalkSelectStmtImpl(SSelectStmt* pSelect, ESqlClause clause, FNodeWalke
|
|||
nodesWalkExprs(pSelect->pOrderByList, walker, pContext);
|
||||
case SQL_CLAUSE_ORDER_BY:
|
||||
nodesWalkExprs(pSelect->pProjectionList, walker, pContext);
|
||||
nodesWalkExprs(pSelect->pProjectionBindList, walker, pContext);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -515,6 +528,7 @@ void nodesRewriteSelectStmt(SSelectStmt* pSelect, ESqlClause clause, FNodeRewrit
|
|||
nodesRewriteExprs(pSelect->pOrderByList, rewriter, pContext);
|
||||
case SQL_CLAUSE_ORDER_BY:
|
||||
nodesRewriteExprs(pSelect->pProjectionList, rewriter, pContext);
|
||||
nodesRewriteExprs(pSelect->pProjectionBindList, rewriter, pContext);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "cmdnodes.h"
|
||||
#include "functionMgt.h"
|
||||
#include "nodes.h"
|
||||
#include "nodesUtil.h"
|
||||
#include "plannodes.h"
|
||||
#include "querynodes.h"
|
||||
|
@ -1125,6 +1126,7 @@ void nodesDestroyNode(SNode* pNode) {
|
|||
SStateWindowNode* pState = (SStateWindowNode*)pNode;
|
||||
nodesDestroyNode(pState->pCol);
|
||||
nodesDestroyNode(pState->pExpr);
|
||||
nodesDestroyNode(pState->pTrueForLimit);
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_SESSION_WINDOW: {
|
||||
|
@ -1239,6 +1241,7 @@ void nodesDestroyNode(SNode* pNode) {
|
|||
nodesDestroyNode(pEvent->pCol);
|
||||
nodesDestroyNode(pEvent->pStartCond);
|
||||
nodesDestroyNode(pEvent->pEndCond);
|
||||
nodesDestroyNode(pEvent->pTrueForLimit);
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_COUNT_WINDOW: {
|
||||
|
@ -1292,6 +1295,7 @@ void nodesDestroyNode(SNode* pNode) {
|
|||
case QUERY_NODE_SELECT_STMT: {
|
||||
SSelectStmt* pStmt = (SSelectStmt*)pNode;
|
||||
nodesDestroyList(pStmt->pProjectionList);
|
||||
nodesDestroyList(pStmt->pProjectionBindList);
|
||||
nodesDestroyNode(pStmt->pFromTable);
|
||||
nodesDestroyNode(pStmt->pWhere);
|
||||
nodesDestroyList(pStmt->pPartitionByList);
|
||||
|
@ -3261,3 +3265,12 @@ int32_t nodesListDeduplicate(SNodeList** ppList) {
|
|||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
void rewriteExprAliasName(SExprNode* pNode, int64_t num) {
|
||||
(void)tsnprintf(pNode->aliasName, TSDB_COL_NAME_LEN, "expr_%x", num);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isRelatedToOtherExpr(SExprNode* pExpr) {
|
||||
return pExpr->relatedTo != 0;
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ TEST_F(NodesCloneTest, stateWindow) {
|
|||
SStateWindowNode* pDstNode = (SStateWindowNode*)pDst;
|
||||
ASSERT_EQ(nodeType(pSrcNode->pCol), nodeType(pDstNode->pCol));
|
||||
ASSERT_EQ(nodeType(pSrcNode->pExpr), nodeType(pDstNode->pExpr));
|
||||
ASSERT_EQ(nodeType(pSrcNode->pTrueForLimit), nodeType(pDstNode->pTrueForLimit));
|
||||
});
|
||||
|
||||
std::unique_ptr<SNode, void (*)(SNode*)> srcNode(nullptr, nodesDestroyNode);
|
||||
|
@ -102,6 +103,7 @@ TEST_F(NodesCloneTest, stateWindow) {
|
|||
SStateWindowNode* pNode = (SStateWindowNode*)srcNode.get();
|
||||
code = nodesMakeNode(QUERY_NODE_COLUMN, &pNode->pCol);
|
||||
code = nodesMakeNode(QUERY_NODE_OPERATOR, &pNode->pExpr);
|
||||
code = nodesMakeNode(QUERY_NODE_VALUE, &pNode->pTrueForLimit);
|
||||
return srcNode.get();
|
||||
}());
|
||||
}
|
||||
|
|
|
@ -155,8 +155,8 @@ SNode* createViewNode(SAstCreateContext* pCxt, SToken* pDbName, SToken* pVie
|
|||
SNode* createLimitNode(SAstCreateContext* pCxt, SNode* pLimit, SNode* pOffset);
|
||||
SNode* createOrderByExprNode(SAstCreateContext* pCxt, SNode* pExpr, EOrder order, ENullOrder nullOrder);
|
||||
SNode* createSessionWindowNode(SAstCreateContext* pCxt, SNode* pCol, SNode* pGap);
|
||||
SNode* createStateWindowNode(SAstCreateContext* pCxt, SNode* pExpr);
|
||||
SNode* createEventWindowNode(SAstCreateContext* pCxt, SNode* pStartCond, SNode* pEndCond);
|
||||
SNode* createStateWindowNode(SAstCreateContext* pCxt, SNode* pExpr, SNode *pTrueForLimit);
|
||||
SNode* createEventWindowNode(SAstCreateContext* pCxt, SNode* pStartCond, SNode* pEndCond, SNode *pTrueForLimit);
|
||||
SNode* createCountWindowNode(SAstCreateContext* pCxt, const SToken* pCountToken, const SToken* pSlidingToken);
|
||||
SNode* createAnomalyWindowNode(SAstCreateContext* pCxt, SNode* pExpr, const SToken* pFuncOpt);
|
||||
SNode* createIntervalWindowNode(SAstCreateContext* pCxt, SNode* pInterval, SNode* pOffset, SNode* pSliding,
|
||||
|
@ -335,6 +335,7 @@ SNode* createDropTSMAStmt(SAstCreateContext* pCxt, bool ignoreNotExists, SNode*
|
|||
SNode* createShowCreateTSMAStmt(SAstCreateContext* pCxt, SNode* pRealTable);
|
||||
SNode* createShowTSMASStmt(SAstCreateContext* pCxt, SNode* dbName);
|
||||
SNode* createShowDiskUsageStmt(SAstCreateContext* pCxt, SNode* dbName, ENodeType type);
|
||||
SNodeList* createColsFuncParamNodeList(SAstCreateContext* pCxt, SNode* pFuncNode, SNodeList* pNodeList, SToken* pAlias);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -1283,6 +1283,7 @@ pseudo_column(A) ::= IROWTS_ORIGIN(B).
|
|||
|
||||
function_expression(A) ::= function_name(B) NK_LP expression_list(C) NK_RP(D). { A = createRawExprNodeExt(pCxt, &B, &D, createFunctionNode(pCxt, &B, C)); }
|
||||
function_expression(A) ::= star_func(B) NK_LP star_func_para_list(C) NK_RP(D). { A = createRawExprNodeExt(pCxt, &B, &D, createFunctionNode(pCxt, &B, C)); }
|
||||
function_expression(A) ::= cols_func(B) NK_LP cols_func_para_list(C) NK_RP(D). { A = createRawExprNodeExt(pCxt, &B, &D, createFunctionNode(pCxt, &B, C)); }
|
||||
function_expression(A) ::=
|
||||
CAST(B) NK_LP expr_or_subquery(C) AS type_name(D) NK_RP(E). { A = createRawExprNodeExt(pCxt, &B, &E, createCastFunctionNode(pCxt, releaseRawExprNode(pCxt, C), D)); }
|
||||
function_expression(A) ::=
|
||||
|
@ -1345,6 +1346,23 @@ star_func(A) ::= FIRST(B).
|
|||
star_func(A) ::= LAST(B). { A = B; }
|
||||
star_func(A) ::= LAST_ROW(B). { A = B; }
|
||||
|
||||
%type cols_func { SToken }
|
||||
%destructor cols_func { }
|
||||
cols_func(A) ::= COLS(B). { A = B; }
|
||||
|
||||
%type cols_func_para_list { SNodeList* }
|
||||
%destructor cols_func_para_list { nodesDestroyList($$); }
|
||||
cols_func_para_list(A) ::= function_expression(B) NK_COMMA cols_func_expression_list(C). { A = createColsFuncParamNodeList(pCxt, B, C, NULL); }
|
||||
|
||||
cols_func_expression(A) ::= expr_or_subquery(B). { A = releaseRawExprNode(pCxt, B); }
|
||||
cols_func_expression(A) ::= expr_or_subquery(B) column_alias(C). { A = setProjectionAlias(pCxt, releaseRawExprNode(pCxt, B), &C);}
|
||||
cols_func_expression(A) ::= expr_or_subquery(B) AS column_alias(C). { A = setProjectionAlias(pCxt, releaseRawExprNode(pCxt, B), &C);}
|
||||
|
||||
%type cols_func_expression_list { SNodeList* }
|
||||
%destructor cols_func_expression_list { nodesDestroyList($$); }
|
||||
cols_func_expression_list(A) ::= cols_func_expression(B). { A = createNodeList(pCxt, B); }
|
||||
cols_func_expression_list(A) ::= cols_func_expression_list(B) NK_COMMA cols_func_expression(C). { A = addNodeToList(pCxt, B, C); }
|
||||
|
||||
%type star_func_para_list { SNodeList* }
|
||||
%destructor star_func_para_list { nodesDestroyList($$); }
|
||||
star_func_para_list(A) ::= NK_STAR(B). { A = createNodeList(pCxt, createColumnNode(pCxt, NULL, &B)); }
|
||||
|
@ -1628,7 +1646,8 @@ partition_item(A) ::= expr_or_subquery(B) AS column_alias(C).
|
|||
twindow_clause_opt(A) ::= . { A = NULL; }
|
||||
twindow_clause_opt(A) ::= SESSION NK_LP column_reference(B) NK_COMMA
|
||||
interval_sliding_duration_literal(C) NK_RP. { A = createSessionWindowNode(pCxt, releaseRawExprNode(pCxt, B), releaseRawExprNode(pCxt, C)); }
|
||||
twindow_clause_opt(A) ::= STATE_WINDOW NK_LP expr_or_subquery(B) NK_RP. { A = createStateWindowNode(pCxt, releaseRawExprNode(pCxt, B)); }
|
||||
twindow_clause_opt(A) ::=
|
||||
STATE_WINDOW NK_LP expr_or_subquery(B) NK_RP true_for_opt(C). { A = createStateWindowNode(pCxt, releaseRawExprNode(pCxt, B), C); }
|
||||
twindow_clause_opt(A) ::= INTERVAL NK_LP interval_sliding_duration_literal(B)
|
||||
NK_RP sliding_opt(C) fill_opt(D). { A = createIntervalWindowNode(pCxt, releaseRawExprNode(pCxt, B), NULL, C, D); }
|
||||
twindow_clause_opt(A) ::=
|
||||
|
@ -1638,8 +1657,8 @@ twindow_clause_opt(A) ::=
|
|||
twindow_clause_opt(A) ::=
|
||||
INTERVAL NK_LP interval_sliding_duration_literal(B) NK_COMMA
|
||||
AUTO(C) NK_RP sliding_opt(D) fill_opt(E). { A = createIntervalWindowNode(pCxt, releaseRawExprNode(pCxt, B), createDurationValueNode(pCxt, &C), D, E); }
|
||||
twindow_clause_opt(A) ::=
|
||||
EVENT_WINDOW START WITH search_condition(B) END WITH search_condition(C). { A = createEventWindowNode(pCxt, B, C); }
|
||||
twindow_clause_opt(A) ::= EVENT_WINDOW START WITH search_condition(B)
|
||||
END WITH search_condition(C) true_for_opt(D). { A = createEventWindowNode(pCxt, B, C, D); }
|
||||
twindow_clause_opt(A) ::=
|
||||
COUNT_WINDOW NK_LP NK_INTEGER(B) NK_RP. { A = createCountWindowNode(pCxt, &B, &B); }
|
||||
twindow_clause_opt(A) ::=
|
||||
|
@ -1717,6 +1736,9 @@ range_opt(A) ::=
|
|||
every_opt(A) ::= . { A = NULL; }
|
||||
every_opt(A) ::= EVERY NK_LP duration_literal(B) NK_RP. { A = releaseRawExprNode(pCxt, B); }
|
||||
|
||||
true_for_opt(A) ::= . { A = NULL; }
|
||||
true_for_opt(A) ::= TRUE_FOR NK_LP interval_sliding_duration_literal(B) NK_RP. { A = releaseRawExprNode(pCxt, B); }
|
||||
|
||||
/************************************************ query_expression ****************************************************/
|
||||
query_expression(A) ::= query_simple(B)
|
||||
order_by_clause_opt(C) slimit_clause_opt(D) limit_clause_opt(E). {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <regex.h>
|
||||
#include <uv.h>
|
||||
|
||||
#include "nodes.h"
|
||||
#include "parAst.h"
|
||||
#include "parUtil.h"
|
||||
#include "tglobal.h"
|
||||
|
@ -356,6 +357,33 @@ SToken getTokenFromRawExprNode(SAstCreateContext* pCxt, SNode* pNode) {
|
|||
return t;
|
||||
}
|
||||
|
||||
SNodeList* createColsFuncParamNodeList(SAstCreateContext* pCxt, SNode* pNode, SNodeList* pNodeList, SToken* pAlias) {
|
||||
CHECK_PARSER_STATUS(pCxt);
|
||||
if (NULL == pNode || QUERY_NODE_RAW_EXPR != nodeType(pNode)) {
|
||||
pCxt->errCode = TSDB_CODE_PAR_SYNTAX_ERROR;
|
||||
}
|
||||
CHECK_PARSER_STATUS(pCxt);
|
||||
SRawExprNode* pRawExpr = (SRawExprNode*)pNode;
|
||||
SNode* pFuncNode = pRawExpr->pNode;
|
||||
if(pFuncNode->type != QUERY_NODE_FUNCTION) {
|
||||
pCxt->errCode = TSDB_CODE_PAR_SYNTAX_ERROR;
|
||||
}
|
||||
CHECK_PARSER_STATUS(pCxt);
|
||||
SNodeList* list = NULL;
|
||||
pCxt->errCode = nodesMakeList(&list);
|
||||
CHECK_MAKE_NODE(list);
|
||||
pCxt->errCode = nodesListAppend(list, pFuncNode);
|
||||
CHECK_PARSER_STATUS(pCxt);
|
||||
pCxt->errCode = nodesListAppendList(list, pNodeList);
|
||||
CHECK_PARSER_STATUS(pCxt);
|
||||
return list;
|
||||
|
||||
_err:
|
||||
nodesDestroyNode(pFuncNode);
|
||||
nodesDestroyList(pNodeList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SNodeList* createNodeList(SAstCreateContext* pCxt, SNode* pNode) {
|
||||
CHECK_PARSER_STATUS(pCxt);
|
||||
SNodeList* list = NULL;
|
||||
|
@ -1332,7 +1360,7 @@ _err:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
SNode* createStateWindowNode(SAstCreateContext* pCxt, SNode* pExpr) {
|
||||
SNode* createStateWindowNode(SAstCreateContext* pCxt, SNode* pExpr, SNode* pTrueForLimit) {
|
||||
SStateWindowNode* state = NULL;
|
||||
CHECK_PARSER_STATUS(pCxt);
|
||||
pCxt->errCode = nodesMakeNode(QUERY_NODE_STATE_WINDOW, (SNode**)&state);
|
||||
|
@ -1340,14 +1368,16 @@ SNode* createStateWindowNode(SAstCreateContext* pCxt, SNode* pExpr) {
|
|||
state->pCol = createPrimaryKeyCol(pCxt, NULL);
|
||||
CHECK_MAKE_NODE(state->pCol);
|
||||
state->pExpr = pExpr;
|
||||
state->pTrueForLimit = pTrueForLimit;
|
||||
return (SNode*)state;
|
||||
_err:
|
||||
nodesDestroyNode((SNode*)state);
|
||||
nodesDestroyNode(pExpr);
|
||||
nodesDestroyNode(pTrueForLimit);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SNode* createEventWindowNode(SAstCreateContext* pCxt, SNode* pStartCond, SNode* pEndCond) {
|
||||
SNode* createEventWindowNode(SAstCreateContext* pCxt, SNode* pStartCond, SNode* pEndCond, SNode* pTrueForLimit) {
|
||||
SEventWindowNode* pEvent = NULL;
|
||||
CHECK_PARSER_STATUS(pCxt);
|
||||
pCxt->errCode = nodesMakeNode(QUERY_NODE_EVENT_WINDOW, (SNode**)&pEvent);
|
||||
|
@ -1356,11 +1386,13 @@ SNode* createEventWindowNode(SAstCreateContext* pCxt, SNode* pStartCond, SNode*
|
|||
CHECK_MAKE_NODE(pEvent->pCol);
|
||||
pEvent->pStartCond = pStartCond;
|
||||
pEvent->pEndCond = pEndCond;
|
||||
pEvent->pTrueForLimit = pTrueForLimit;
|
||||
return (SNode*)pEvent;
|
||||
_err:
|
||||
nodesDestroyNode((SNode*)pEvent);
|
||||
nodesDestroyNode(pStartCond);
|
||||
nodesDestroyNode(pEndCond);
|
||||
nodesDestroyNode(pTrueForLimit);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -355,10 +355,12 @@ static SKeyword keywordTable[] = {
|
|||
{"FORCE_WINDOW_CLOSE", TK_FORCE_WINDOW_CLOSE},
|
||||
{"DISK_INFO", TK_DISK_INFO},
|
||||
{"AUTO", TK_AUTO},
|
||||
{"COLS", TK_COLS},
|
||||
{"NOTIFY", TK_NOTIFY},
|
||||
{"ON_FAILURE", TK_ON_FAILURE},
|
||||
{"NOTIFY_HISTORY", TK_NOTIFY_HISTORY},
|
||||
{"REGEXP", TK_REGEXP},
|
||||
{"TRUE_FOR", TK_TRUE_FOR}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
|
|
@ -13,8 +13,13 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "nodes.h"
|
||||
#include "parInt.h"
|
||||
#include "parTranslater.h"
|
||||
#include <stdint.h>
|
||||
#include "query.h"
|
||||
#include "querynodes.h"
|
||||
#include "taoserror.h"
|
||||
#include "tdatablock.h"
|
||||
|
||||
#include "catalog.h"
|
||||
|
@ -1099,6 +1104,15 @@ static bool isForecastPseudoColumnFunc(const SNode* pNode) {
|
|||
return (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsForecastPseudoColumnFunc(((SFunctionNode*)pNode)->funcId));
|
||||
}
|
||||
|
||||
static bool isColsFunctionResult(const SNode* pNode) {
|
||||
return ((nodesIsExprNode(pNode)) && (isRelatedToOtherExpr((SExprNode*)pNode)));
|
||||
}
|
||||
|
||||
static bool isInvalidColsBindFunction(const SFunctionNode* pFunc) {
|
||||
return (pFunc->node.bindExprID != 0 && (!fmIsSelectFunc(pFunc->funcId) || fmIsMultiRowsFunc(pFunc->funcId) ||
|
||||
fmIsIndefiniteRowsFunc(pFunc->funcId)));
|
||||
}
|
||||
|
||||
#ifdef BUILD_NO_CALL
|
||||
static bool isTimelineFunc(const SNode* pNode) {
|
||||
return (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsTimelineFunc(((SFunctionNode*)pNode)->funcId));
|
||||
|
@ -1125,6 +1139,10 @@ static bool isVectorFunc(const SNode* pNode) {
|
|||
return (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsVectorFunc(((SFunctionNode*)pNode)->funcId));
|
||||
}
|
||||
|
||||
static bool isColsFunc(const SNode* pNode) {
|
||||
return (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsSelectColsFunc(((SFunctionNode*)pNode)->funcId));
|
||||
}
|
||||
|
||||
static bool isDistinctOrderBy(STranslateContext* pCxt) {
|
||||
return (SQL_CLAUSE_ORDER_BY == pCxt->currClause && isSelectStmt(pCxt->pCurrStmt) &&
|
||||
((SSelectStmt*)pCxt->pCurrStmt)->isDistinct);
|
||||
|
@ -1557,24 +1575,27 @@ static int32_t findAndSetColumn(STranslateContext* pCxt, SColumnNode** pColRef,
|
|||
STempTableNode* pTempTable = (STempTableNode*)pTable;
|
||||
SNodeList* pProjectList = getProjectList(pTempTable->pSubquery);
|
||||
SNode* pNode;
|
||||
SExprNode* pFoundExpr = NULL;
|
||||
FOREACH(pNode, pProjectList) {
|
||||
SExprNode* pExpr = (SExprNode*)pNode;
|
||||
if (0 == strcmp(pCol->colName, pExpr->aliasName)) {
|
||||
if (*pFound) {
|
||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AMBIGUOUS_COLUMN, pCol->colName);
|
||||
}
|
||||
code = setColumnInfoByExpr(pTempTable, pExpr, pColRef);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
break;
|
||||
}
|
||||
pFoundExpr = pExpr;
|
||||
*pFound = true;
|
||||
} else if (isPrimaryKeyImpl(pNode) && isInternalPrimaryKey(pCol)) {
|
||||
code = setColumnInfoByExpr(pTempTable, pExpr, pColRef);
|
||||
if (TSDB_CODE_SUCCESS != code) break;
|
||||
pFoundExpr = pExpr;
|
||||
pCol->isPrimTs = true;
|
||||
*pFound = true;
|
||||
}
|
||||
}
|
||||
if (pFoundExpr) {
|
||||
code = setColumnInfoByExpr(pTempTable, pFoundExpr, pColRef);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
@ -2331,7 +2352,7 @@ static EDealRes translateOperator(STranslateContext* pCxt, SOperatorNode* pOp) {
|
|||
|
||||
static EDealRes haveVectorFunction(SNode* pNode, void* pContext) {
|
||||
if (isAggFunc(pNode) || isIndefiniteRowsFunc(pNode) || isWindowPseudoColumnFunc(pNode) ||
|
||||
isInterpPseudoColumnFunc(pNode) || isForecastPseudoColumnFunc(pNode)) {
|
||||
isInterpPseudoColumnFunc(pNode) || isForecastPseudoColumnFunc(pNode) || isColsFunctionResult(pNode)) {
|
||||
*((bool*)pContext) = true;
|
||||
return DEAL_RES_END;
|
||||
}
|
||||
|
@ -2479,9 +2500,9 @@ static int32_t rewriteCountTbname(STranslateContext* pCxt, SFunctionNode* pCount
|
|||
return code;
|
||||
}
|
||||
|
||||
static bool hasInvalidFuncNesting(SNodeList* pParameterList) {
|
||||
static bool hasInvalidFuncNesting(SFunctionNode* pFunc) {
|
||||
bool hasInvalidFunc = false;
|
||||
nodesWalkExprs(pParameterList, haveVectorFunction, &hasInvalidFunc);
|
||||
nodesWalkExprs(pFunc->pParameterList, haveVectorFunction, &hasInvalidFunc);
|
||||
return hasInvalidFunc;
|
||||
}
|
||||
|
||||
|
@ -2503,7 +2524,7 @@ static int32_t translateAggFunc(STranslateContext* pCxt, SFunctionNode* pFunc) {
|
|||
if (beforeHaving(pCxt->currClause)) {
|
||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION);
|
||||
}
|
||||
if (hasInvalidFuncNesting(pFunc->pParameterList)) {
|
||||
if (hasInvalidFuncNesting(pFunc)) {
|
||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
|
||||
}
|
||||
// The auto-generated COUNT function in the DELETE statement is legal
|
||||
|
@ -2547,7 +2568,7 @@ static int32_t translateIndefiniteRowsFunc(STranslateContext* pCxt, SFunctionNod
|
|||
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC,
|
||||
"%s function is not supported in window query or group query", pFunc->functionName);
|
||||
}
|
||||
if (hasInvalidFuncNesting(pFunc->pParameterList)) {
|
||||
if (hasInvalidFuncNesting(pFunc)) {
|
||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
|
||||
}
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
@ -2562,7 +2583,7 @@ static int32_t translateMultiRowsFunc(STranslateContext* pCxt, SFunctionNode* pF
|
|||
((SSelectStmt*)pCxt->pCurrStmt)->hasMultiRowsFunc) {
|
||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC);
|
||||
}
|
||||
if (hasInvalidFuncNesting(pFunc->pParameterList)) {
|
||||
if (hasInvalidFuncNesting(pFunc)) {
|
||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
|
||||
}
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
@ -2593,7 +2614,7 @@ static int32_t translateInterpFunc(STranslateContext* pCxt, SFunctionNode* pFunc
|
|||
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC,
|
||||
"%s function is not supported in window query or group query", pFunc->functionName);
|
||||
}
|
||||
if (hasInvalidFuncNesting(pFunc->pParameterList)) {
|
||||
if (hasInvalidFuncNesting(pFunc)) {
|
||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
|
||||
}
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
@ -2659,7 +2680,7 @@ static int32_t translateForecastFunc(STranslateContext* pCxt, SFunctionNode* pFu
|
|||
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC,
|
||||
"%s function is not supported in window query or group query", pFunc->functionName);
|
||||
}
|
||||
if (hasInvalidFuncNesting(pFunc->pParameterList)) {
|
||||
if (hasInvalidFuncNesting(pFunc)) {
|
||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
|
||||
}
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
@ -2889,6 +2910,9 @@ static int32_t calcSelectFuncNum(SFunctionNode* pFunc, int32_t currSelectFuncNum
|
|||
if (fmIsCumulativeFunc(pFunc->funcId)) {
|
||||
return currSelectFuncNum > 0 ? currSelectFuncNum : 1;
|
||||
}
|
||||
if(fmIsSelectColsFunc(pFunc->funcId)) {
|
||||
return currSelectFuncNum;
|
||||
}
|
||||
return currSelectFuncNum + ((fmIsMultiResFunc(pFunc->funcId) && !fmIsLastRowFunc(pFunc->funcId))
|
||||
? getMultiResFuncNum(pFunc->pParameterList)
|
||||
: 1);
|
||||
|
@ -3314,6 +3338,10 @@ static EDealRes translateFunction(STranslateContext* pCxt, SFunctionNode** pFunc
|
|||
pCxt->errCode = TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION;
|
||||
}
|
||||
}
|
||||
if (isInvalidColsBindFunction(*pFunc)) {
|
||||
pCxt->errCode = TSDB_CODE_PAR_INVALID_COLS_SELECTFUNC;
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == pCxt->errCode) {
|
||||
pCxt->errCode = translateFunctionImpl(pCxt, pFunc);
|
||||
}
|
||||
|
@ -3555,6 +3583,9 @@ static EDealRes rewriteColToSelectValFunc(STranslateContext* pCxt, SNode** pNode
|
|||
tstrncpy(pFunc->functionName, "_select_value", TSDB_FUNC_NAME_LEN);
|
||||
tstrncpy(pFunc->node.aliasName, ((SExprNode*)*pNode)->aliasName, TSDB_COL_NAME_LEN);
|
||||
tstrncpy(pFunc->node.userAlias, ((SExprNode*)*pNode)->userAlias, TSDB_COL_NAME_LEN);
|
||||
|
||||
pFunc->node.relatedTo = ((SExprNode*)*pNode)->relatedTo;
|
||||
pFunc->node.bindExprID = ((SExprNode*)*pNode)->bindExprID;
|
||||
pCxt->errCode = nodesListMakeAppend(&pFunc->pParameterList, *pNode);
|
||||
if (TSDB_CODE_SUCCESS == pCxt->errCode) {
|
||||
pCxt->errCode = getFuncInfo(pCxt, pFunc);
|
||||
|
@ -3827,6 +3858,7 @@ static EDealRes doCheckExprForGroupBy(SNode** pNode, void* pContext) {
|
|||
if (isVectorFunc(*pNode) && !isDistinctOrderBy(pCxt)) {
|
||||
return DEAL_RES_IGNORE_CHILD;
|
||||
}
|
||||
bool isSingleTable = fromSingleTable(((SSelectStmt*)pCxt->pCurrStmt)->pFromTable);
|
||||
SNode* pGroupNode = NULL;
|
||||
FOREACH(pGroupNode, getGroupByList(pCxt)) {
|
||||
SNode* pActualNode = getGroupByNode(pGroupNode);
|
||||
|
@ -3836,10 +3868,13 @@ static EDealRes doCheckExprForGroupBy(SNode** pNode, void* pContext) {
|
|||
if (IsEqualTbNameFuncNode(pSelect, pActualNode, *pNode)) {
|
||||
return rewriteExprToGroupKeyFunc(pCxt, pNode);
|
||||
}
|
||||
if (isTbnameFuction(pActualNode) && QUERY_NODE_COLUMN == nodeType(*pNode) &&
|
||||
if ((isTbnameFuction(pActualNode) || isSingleTable) && QUERY_NODE_COLUMN == nodeType(*pNode) &&
|
||||
((SColumnNode*)*pNode)->colType == COLUMN_TYPE_TAG) {
|
||||
return rewriteExprToSelectTagFunc(pCxt, pNode);
|
||||
}
|
||||
if(isSingleTable && isTbnameFuction(*pNode)) {
|
||||
return rewriteExprToSelectTagFunc(pCxt, pNode);
|
||||
}
|
||||
}
|
||||
SNode* pPartKey = NULL;
|
||||
bool partionByTbname = hasTbnameFunction(pSelect->pPartitionByList);
|
||||
|
@ -3863,17 +3898,29 @@ static EDealRes doCheckExprForGroupBy(SNode** pNode, void* pContext) {
|
|||
}
|
||||
}
|
||||
|
||||
if (isScanPseudoColumnFunc(*pNode) || QUERY_NODE_COLUMN == nodeType(*pNode)) {
|
||||
if (pSelect->selectFuncNum > 1 || (isDistinctOrderBy(pCxt) && pCxt->currClause == SQL_CLAUSE_ORDER_BY)) {
|
||||
if (isScanPseudoColumnFunc(*pNode)) {
|
||||
if (((pSelect->selectFuncNum > 1 && pCxt->stableQuery) ||
|
||||
(isDistinctOrderBy(pCxt) && pCxt->currClause == SQL_CLAUSE_ORDER_BY)) &&
|
||||
!isRelatedToOtherExpr((SExprNode*)*pNode)) {
|
||||
return generateDealNodeErrMsg(pCxt, getGroupByErrorCode(pCxt), ((SExprNode*)(*pNode))->userAlias);
|
||||
}
|
||||
}
|
||||
|
||||
if (QUERY_NODE_COLUMN == nodeType(*pNode)) {
|
||||
if (((pSelect->selectFuncNum > 1) || (isDistinctOrderBy(pCxt) && pCxt->currClause == SQL_CLAUSE_ORDER_BY)) &&
|
||||
!isRelatedToOtherExpr((SExprNode*)*pNode)) {
|
||||
return generateDealNodeErrMsg(pCxt, getGroupByErrorCode(pCxt), ((SExprNode*)(*pNode))->userAlias);
|
||||
}
|
||||
}
|
||||
|
||||
if (isScanPseudoColumnFunc(*pNode) || QUERY_NODE_COLUMN == nodeType(*pNode)) {
|
||||
if (isWindowJoinStmt(pSelect) &&
|
||||
(isWindowJoinProbeTableCol(pSelect, *pNode) || isWindowJoinGroupCol(pSelect, *pNode) ||
|
||||
(isWindowJoinSubTbname(pSelect, *pNode)) || isWindowJoinSubTbTag(pSelect, *pNode))) {
|
||||
return rewriteExprToGroupKeyFunc(pCxt, pNode);
|
||||
}
|
||||
|
||||
if (pSelect->hasOtherVectorFunc || !pSelect->hasSelectFunc) {
|
||||
if ((pSelect->hasOtherVectorFunc || !pSelect->hasSelectFunc) && !isRelatedToOtherExpr((SExprNode*)*pNode)) {
|
||||
return generateDealNodeErrMsg(pCxt, getGroupByErrorCode(pCxt), ((SExprNode*)(*pNode))->userAlias);
|
||||
}
|
||||
|
||||
|
@ -3920,6 +3967,7 @@ static int32_t rewriteColsToSelectValFunc(STranslateContext* pCxt, SSelectStmt*
|
|||
typedef struct CheckAggColCoexistCxt {
|
||||
STranslateContext* pTranslateCxt;
|
||||
bool existCol;
|
||||
bool hasColFunc;
|
||||
SNodeList* pColList;
|
||||
} CheckAggColCoexistCxt;
|
||||
|
||||
|
@ -3928,6 +3976,10 @@ static EDealRes doCheckAggColCoexist(SNode** pNode, void* pContext) {
|
|||
if (isVectorFunc(*pNode)) {
|
||||
return DEAL_RES_IGNORE_CHILD;
|
||||
}
|
||||
if(isColsFunctionResult(*pNode)) {
|
||||
pCxt->hasColFunc = true;
|
||||
}
|
||||
|
||||
SNode* pPartKey = NULL;
|
||||
bool partionByTbname = false;
|
||||
if (fromSingleTable(((SSelectStmt*)pCxt->pTranslateCxt->pCurrStmt)->pFromTable) ||
|
||||
|
@ -3947,7 +3999,8 @@ static EDealRes doCheckAggColCoexist(SNode** pNode, void* pContext) {
|
|||
((QUERY_NODE_COLUMN == nodeType(*pNode) && ((SColumnNode*)*pNode)->colType == COLUMN_TYPE_TAG))) {
|
||||
return rewriteExprToSelectTagFunc(pCxt->pTranslateCxt, pNode);
|
||||
}
|
||||
if (isScanPseudoColumnFunc(*pNode) || QUERY_NODE_COLUMN == nodeType(*pNode)) {
|
||||
if ((isScanPseudoColumnFunc(*pNode) || QUERY_NODE_COLUMN == nodeType(*pNode)) &&
|
||||
((!nodesIsExprNode(*pNode) || !isRelatedToOtherExpr((SExprNode*)*pNode)))) {
|
||||
pCxt->existCol = true;
|
||||
}
|
||||
return DEAL_RES_CONTINUE;
|
||||
|
@ -4006,7 +4059,7 @@ static int32_t checkAggColCoexist(STranslateContext* pCxt, SSelectStmt* pSelect)
|
|||
if (!pSelect->onlyHasKeepOrderFunc) {
|
||||
pSelect->timeLineResMode = TIME_LINE_NONE;
|
||||
}
|
||||
CheckAggColCoexistCxt cxt = {.pTranslateCxt = pCxt, .existCol = false};
|
||||
CheckAggColCoexistCxt cxt = {.pTranslateCxt = pCxt, .existCol = false, .hasColFunc = false};
|
||||
nodesRewriteExprs(pSelect->pProjectionList, doCheckAggColCoexist, &cxt);
|
||||
if (!pSelect->isDistinct) {
|
||||
nodesRewriteExprs(pSelect->pOrderByList, doCheckAggColCoexist, &cxt);
|
||||
|
@ -4018,6 +4071,9 @@ static int32_t checkAggColCoexist(STranslateContext* pCxt, SSelectStmt* pSelect)
|
|||
if (cxt.existCol) {
|
||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_SINGLE_GROUP);
|
||||
}
|
||||
if (cxt.hasColFunc) {
|
||||
return rewriteColsToSelectValFunc(pCxt, pSelect);
|
||||
}
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -5425,9 +5481,38 @@ static int32_t translateClausePosition(STranslateContext* pCxt, SNodeList* pProj
|
|||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t rewriteColsFunction(STranslateContext* pCxt, SNodeList** nodeList, SNodeList** selectFuncList);
|
||||
static int32_t rewriteHavingColsNode(STranslateContext* pCxt, SNode** pNode, SNodeList** selectFuncList);
|
||||
|
||||
static int32_t prepareColumnExpansion(STranslateContext* pCxt, ESqlClause clause, SSelectStmt* pSelect) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
int32_t len = LIST_LENGTH(pSelect->pProjectionBindList);
|
||||
if (clause == SQL_CLAUSE_SELECT) {
|
||||
code = rewriteColsFunction(pCxt, &pSelect->pProjectionList, &pSelect->pProjectionBindList);
|
||||
} else if (clause == SQL_CLAUSE_HAVING) {
|
||||
code = rewriteHavingColsNode(pCxt, &pSelect->pHaving, &pSelect->pProjectionBindList);
|
||||
} else if (clause == SQL_CLAUSE_ORDER_BY) {
|
||||
code = rewriteColsFunction(pCxt, &pSelect->pOrderByList, &pSelect->pProjectionBindList);
|
||||
} else {
|
||||
code =
|
||||
generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_WRONG_VALUE_TYPE, "Invalid clause for column expansion");
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code && LIST_LENGTH(pSelect->pProjectionBindList) > len) {
|
||||
code = translateExprList(pCxt, pSelect->pProjectionBindList);
|
||||
}
|
||||
if (pSelect->pProjectionBindList != NULL) {
|
||||
pSelect->hasAggFuncs = true;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t translateOrderBy(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
bool other;
|
||||
int32_t code = translateClausePosition(pCxt, pSelect->pProjectionList, pSelect->pOrderByList, &other);
|
||||
int32_t code = prepareColumnExpansion(pCxt, SQL_CLAUSE_ORDER_BY, pSelect);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
return code;
|
||||
}
|
||||
code = translateClausePosition(pCxt, pSelect->pProjectionList, pSelect->pOrderByList, &other);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
if (0 == LIST_LENGTH(pSelect->pOrderByList)) {
|
||||
NODES_DESTORY_LIST(pSelect->pOrderByList);
|
||||
|
@ -5528,7 +5613,7 @@ static int32_t rewriteProjectAlias(SNodeList* pProjectionList) {
|
|||
if ('\0' == pExpr->userAlias[0]) {
|
||||
tstrncpy(pExpr->userAlias, pExpr->aliasName, TSDB_COL_NAME_LEN);
|
||||
}
|
||||
snprintf(pExpr->aliasName, TSDB_COL_NAME_LEN,"#expr_%d", no++);
|
||||
rewriteExprAliasName(pExpr, no++);
|
||||
}
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
@ -5557,14 +5642,14 @@ static int32_t checkProjectAlias(STranslateContext* pCxt, SNodeList* pProjection
|
|||
}
|
||||
|
||||
static int32_t translateProjectionList(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
if (!pSelect->isSubquery) {
|
||||
return rewriteProjectAlias(pSelect->pProjectionList);
|
||||
} else {
|
||||
SNode* pNode;
|
||||
int32_t projIdx = 1;
|
||||
FOREACH(pNode, pSelect->pProjectionList) { ((SExprNode*)pNode)->projIdx = projIdx++; }
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
||||
if (!pSelect->isSubquery) {
|
||||
return rewriteProjectAlias(pSelect->pProjectionList);
|
||||
}
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
typedef struct SReplaceGroupByAliasCxt {
|
||||
|
@ -5646,7 +5731,10 @@ static int32_t translatePartitionByList(STranslateContext* pCxt, SSelectStmt* pS
|
|||
|
||||
static int32_t translateSelectList(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
pCxt->currClause = SQL_CLAUSE_SELECT;
|
||||
int32_t code = translateExprList(pCxt, pSelect->pProjectionList);
|
||||
int32_t code = prepareColumnExpansion(pCxt, SQL_CLAUSE_SELECT, pSelect);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = translateExprList(pCxt, pSelect->pProjectionList);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = translateStar(pCxt, pSelect);
|
||||
}
|
||||
|
@ -5670,10 +5758,18 @@ static int32_t translateSelectList(STranslateContext* pCxt, SSelectStmt* pSelect
|
|||
}
|
||||
|
||||
static int32_t translateHaving(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
if (NULL == pSelect->pGroupByList && NULL == pSelect->pPartitionByList && NULL == pSelect->pWindow &&
|
||||
!isWindowJoinStmt(pSelect) && NULL != pSelect->pHaving) {
|
||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION);
|
||||
}
|
||||
pCxt->currClause = SQL_CLAUSE_HAVING;
|
||||
if (NULL != pSelect->pHaving) {
|
||||
code = prepareColumnExpansion(pCxt, SQL_CLAUSE_HAVING, pSelect);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
if (isWindowJoinStmt(pSelect)) {
|
||||
if (NULL != pSelect->pHaving) {
|
||||
bool hasFunc = false;
|
||||
|
@ -5683,9 +5779,7 @@ static int32_t translateHaving(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
|||
}
|
||||
}
|
||||
}
|
||||
pCxt->currClause = SQL_CLAUSE_HAVING;
|
||||
int32_t code = translateExpr(pCxt, &pSelect->pHaving);
|
||||
return code;
|
||||
return translateExpr(pCxt, &pSelect->pHaving);
|
||||
}
|
||||
|
||||
static int32_t translateGroupBy(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
|
@ -6043,6 +6137,20 @@ static int32_t checkStateWindowForStream(STranslateContext* pCxt, SSelectStmt* p
|
|||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t checkTrueForLimit(STranslateContext *pCxt, SNode *pNode) {
|
||||
SValueNode *pTrueForLimit = (SValueNode *)pNode;
|
||||
if (pTrueForLimit == NULL) {
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
if (pTrueForLimit->datum.i < 0) {
|
||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_TRUE_FOR_NEGATIVE);
|
||||
}
|
||||
if (IS_CALENDAR_TIME_DURATION(pTrueForLimit->unit)) {
|
||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_TRUE_FOR_UNIT);
|
||||
}
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t translateStateWindow(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
if (QUERY_NODE_TEMP_TABLE == nodeType(pSelect->pFromTable) &&
|
||||
!isGlobalTimeLineQuery(((STempTableNode*)pSelect->pFromTable)->pSubquery)) {
|
||||
|
@ -6055,6 +6163,9 @@ static int32_t translateStateWindow(STranslateContext* pCxt, SSelectStmt* pSelec
|
|||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = checkStateWindowForStream(pCxt, pSelect);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = checkTrueForLimit(pCxt, pState->pTrueForLimit);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -6081,7 +6192,7 @@ static int32_t translateEventWindow(STranslateContext* pCxt, SSelectStmt* pSelec
|
|||
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_TIMELINE_QUERY,
|
||||
"EVENT_WINDOW requires valid time series input");
|
||||
}
|
||||
return TSDB_CODE_SUCCESS;
|
||||
return checkTrueForLimit(pCxt, ((SEventWindowNode*)pSelect->pWindow)->pTrueForLimit);
|
||||
}
|
||||
|
||||
static int32_t translateCountWindow(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
|
@ -7310,6 +7421,307 @@ static int32_t translateSelectWithoutFrom(STranslateContext* pCxt, SSelectStmt*
|
|||
pCxt->dual = true;
|
||||
return translateExprList(pCxt, pSelect->pProjectionList);
|
||||
}
|
||||
typedef struct SCheckColsFuncCxt {
|
||||
bool hasColsFunc;
|
||||
SNodeList** selectFuncList;
|
||||
int32_t status;
|
||||
} SCheckColsFuncCxt;
|
||||
|
||||
static bool isColsFuncByName(SFunctionNode* pFunc) {
|
||||
if (strcasecmp(pFunc->functionName, "cols") != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isMultiColsFuncNode(SNode* pNode) {
|
||||
if (QUERY_NODE_FUNCTION == nodeType(pNode)) {
|
||||
SFunctionNode* pFunc = (SFunctionNode*)pNode;
|
||||
if (isColsFuncByName(pFunc)) {
|
||||
if (pFunc->pParameterList->length > 2) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef struct SBindTupleFuncCxt {
|
||||
SNode* root;
|
||||
int32_t bindExprID;
|
||||
} SBindTupleFuncCxt;
|
||||
|
||||
static EDealRes pushDownBindSelectFunc(SNode** pNode, void* pContext) {
|
||||
SBindTupleFuncCxt* pCxt = pContext;
|
||||
if (nodesIsExprNode(*pNode)) {
|
||||
SExprNode* pExpr = (SExprNode*)*pNode;
|
||||
pExpr->relatedTo = pCxt->bindExprID;
|
||||
if (nodeType(*pNode) != QUERY_NODE_COLUMN) {
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
|
||||
if (*pNode != pCxt->root) {
|
||||
int len = strlen(pExpr->aliasName);
|
||||
if (len + TSDB_COL_NAME_EXLEN >= TSDB_COL_NAME_LEN) {
|
||||
char buffer[TSDB_COL_NAME_EXLEN + TSDB_COL_NAME_LEN + 1] = {0};
|
||||
(void)tsnprintf(buffer, sizeof(buffer), "%s.%d", pExpr->aliasName, pExpr->relatedTo);
|
||||
uint64_t hashVal = MurmurHash3_64(buffer, TSDB_COL_NAME_EXLEN + TSDB_COL_NAME_LEN + 1);
|
||||
(void)tsnprintf(pExpr->aliasName, TSDB_COL_NAME_EXLEN, "%" PRIu64, hashVal);
|
||||
} else {
|
||||
(void)tsnprintf(pExpr->aliasName + len, TSDB_COL_NAME_EXLEN, ".%d", pExpr->relatedTo);
|
||||
}
|
||||
}
|
||||
}
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
|
||||
static int32_t getSelectFuncIndex(SNodeList* FuncNodeList, SNode* pSelectFunc) {
|
||||
SNode* pNode = NULL;
|
||||
int32_t selectFuncIndex = 0;
|
||||
FOREACH(pNode, FuncNodeList) {
|
||||
++selectFuncIndex;
|
||||
if (nodesEqualNode(pNode, pSelectFunc)) {
|
||||
return selectFuncIndex;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static EDealRes checkHasColsFunc(SNode** pNode, void* pContext){
|
||||
if (QUERY_NODE_FUNCTION == nodeType(*pNode)) {
|
||||
SFunctionNode* pFunc = (SFunctionNode*)*pNode;
|
||||
if (isColsFuncByName(pFunc)) {
|
||||
*(bool*)pContext = true;
|
||||
return DEAL_RES_END;
|
||||
}
|
||||
}
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
|
||||
static int32_t checkMultColsFuncParam(SNodeList* pParameterList) {
|
||||
if (!pParameterList || pParameterList->length < 2) {
|
||||
return TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||
}
|
||||
int32_t index = 0;
|
||||
SNode* pNode = NULL;
|
||||
FOREACH(pNode, pParameterList) {
|
||||
if (index == 0) { // the first parameter is select function
|
||||
if (QUERY_NODE_FUNCTION != nodeType(pNode) || isColsFuncByName((SFunctionNode*)pNode)) {
|
||||
return TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||
}
|
||||
SFunctionNode* pFunc = (SFunctionNode*)pNode;
|
||||
// pFunc->funcId is zero at here, so need to check at * step
|
||||
// if(!fmIsSelectFunc(pFunc->funcId)) {
|
||||
// return TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||
// }
|
||||
SNode* pTmpNode = NULL;
|
||||
FOREACH(pTmpNode, pFunc->pParameterList) {
|
||||
bool hasColsFunc = false;
|
||||
nodesRewriteExpr(&pTmpNode, checkHasColsFunc, (void*)&hasColsFunc);
|
||||
if (hasColsFunc) {
|
||||
return TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool hasColsFunc = false;
|
||||
nodesRewriteExpr(&pNode, checkHasColsFunc, &hasColsFunc);
|
||||
if (hasColsFunc) {
|
||||
return TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||
}
|
||||
}
|
||||
++index;
|
||||
}
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static EDealRes rewriteSingleColsFunc(SNode** pNode, void* pContext) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
if (QUERY_NODE_FUNCTION != nodeType(*pNode)) {
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
SCheckColsFuncCxt* pCxt = pContext;
|
||||
SFunctionNode* pFunc = (SFunctionNode*)*pNode;
|
||||
if (isColsFuncByName(pFunc)) {
|
||||
if(pFunc->pParameterList->length > 2) {
|
||||
pCxt->status = TSDB_CODE_PAR_INVALID_COLS_SELECTFUNC;
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
SNode* pSelectFunc = nodesListGetNode(pFunc->pParameterList, 0);
|
||||
SNode* pExpr = nodesListGetNode(pFunc->pParameterList, 1);
|
||||
if (nodeType(pSelectFunc) != QUERY_NODE_FUNCTION || isColsFuncByName((SFunctionNode*)pSelectFunc)) {
|
||||
pCxt->status = TSDB_CODE_PAR_INVALID_COLS_SELECTFUNC;
|
||||
parserError("%s Invalid cols function, the first parameter must be a select function", __func__);
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
if (pFunc->node.asAlias) {
|
||||
if (((SExprNode*)pExpr)->asAlias) {
|
||||
pCxt->status = TSDB_CODE_INVALID_COLS_ALIAS;
|
||||
parserError("%s Invalid using alias for cols function", __func__);
|
||||
return DEAL_RES_ERROR;
|
||||
} else {
|
||||
((SExprNode*)pExpr)->asAlias = true;
|
||||
tstrncpy(((SExprNode*)pExpr)->userAlias, pFunc->node.userAlias, TSDB_COL_NAME_LEN);
|
||||
}
|
||||
}
|
||||
if(*pCxt->selectFuncList == NULL) {
|
||||
code = nodesMakeList(pCxt->selectFuncList);
|
||||
if (NULL == *pCxt->selectFuncList) {
|
||||
pCxt->status = code;
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
}
|
||||
int32_t selectFuncCount = (*pCxt->selectFuncList)->length;
|
||||
int32_t selectFuncIndex = getSelectFuncIndex(*pCxt->selectFuncList, pSelectFunc);
|
||||
if (selectFuncIndex == 0) {
|
||||
++selectFuncCount;
|
||||
selectFuncIndex = selectFuncCount;
|
||||
SNode* pNewNode = NULL;
|
||||
code = nodesCloneNode(pSelectFunc, &pNewNode);
|
||||
if(code) goto _end;
|
||||
((SExprNode*)pNewNode)->bindExprID = selectFuncIndex;
|
||||
code = nodesListMakeStrictAppend(pCxt->selectFuncList, pNewNode);
|
||||
if(code) goto _end;
|
||||
}
|
||||
|
||||
SNode* pNewNode = NULL;
|
||||
code = nodesCloneNode(pExpr, &pNewNode);
|
||||
if(code) goto _end;
|
||||
if (nodesIsExprNode(pNewNode)) {
|
||||
SBindTupleFuncCxt pCxt = {pNewNode, selectFuncIndex};
|
||||
nodesRewriteExpr(&pNewNode, pushDownBindSelectFunc, &pCxt);
|
||||
} else {
|
||||
pCxt->status = TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||
parserError("%s Invalid cols function, the first parameter must be a select function", __func__);
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
nodesDestroyNode(*pNode);
|
||||
*pNode = pNewNode;
|
||||
}
|
||||
return DEAL_RES_CONTINUE;
|
||||
_end:
|
||||
pCxt->status = code;
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
|
||||
static int32_t rewriteHavingColsNode(STranslateContext* pCxt, SNode** pNode, SNodeList** selectFuncList) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
if(!pNode || *pNode == NULL) return code;
|
||||
if (isMultiColsFuncNode(*pNode)) {
|
||||
parserWarn("%s Invalid using multi cols func in having.", __func__);
|
||||
return TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||
} else {
|
||||
SCheckColsFuncCxt pSelectFuncCxt = {false, selectFuncList, TSDB_CODE_SUCCESS};
|
||||
nodesRewriteExpr(pNode, rewriteSingleColsFunc, &pSelectFuncCxt);
|
||||
if (pSelectFuncCxt.status != TSDB_CODE_SUCCESS) {
|
||||
return pSelectFuncCxt.status;
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t rewriteColsFunction(STranslateContext* pCxt, SNodeList** nodeList, SNodeList** selectFuncList) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
bool needRewrite = false;
|
||||
SNode** pNode = NULL;
|
||||
FOREACH_FOR_REWRITE(pNode, *nodeList) {
|
||||
if (isMultiColsFuncNode(*pNode)) {
|
||||
code = checkMultColsFuncParam(((SFunctionNode*)*pNode)->pParameterList);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
return code;
|
||||
}
|
||||
needRewrite = true;
|
||||
} else {
|
||||
SCheckColsFuncCxt pSelectFuncCxt = {false, selectFuncList, TSDB_CODE_SUCCESS};
|
||||
nodesRewriteExpr(pNode, rewriteSingleColsFunc, &pSelectFuncCxt);
|
||||
if (pSelectFuncCxt.status != TSDB_CODE_SUCCESS) {
|
||||
return pSelectFuncCxt.status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SNodeList* pNewNodeList = NULL;
|
||||
SNode* pNewNode = NULL;
|
||||
if (needRewrite) {
|
||||
if (pCxt->createStream) {
|
||||
return TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||
}
|
||||
code = nodesMakeList(&pNewNodeList);
|
||||
if (NULL == pNewNodeList) {
|
||||
return code;
|
||||
}
|
||||
if (*selectFuncList == NULL) {
|
||||
code = nodesMakeList(selectFuncList);
|
||||
if (NULL == *selectFuncList) {
|
||||
nodesDestroyList(pNewNodeList);
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t nums = 0;
|
||||
int32_t selectFuncCount = (*selectFuncList)->length;
|
||||
SNode* pTmpNode = NULL;
|
||||
FOREACH(pTmpNode, *nodeList) {
|
||||
if (isMultiColsFuncNode(pTmpNode)) {
|
||||
SFunctionNode* pFunc = (SFunctionNode*)pTmpNode;
|
||||
if(pFunc->node.asAlias) {
|
||||
code = TSDB_CODE_INVALID_COLS_ALIAS;
|
||||
parserError("%s Invalid using alias for cols function", __func__);
|
||||
goto _end;
|
||||
}
|
||||
|
||||
SNode* pSelectFunc = nodesListGetNode(pFunc->pParameterList, 0);
|
||||
if (nodeType(pSelectFunc) != QUERY_NODE_FUNCTION) {
|
||||
code = TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||
parserError("%s Invalid cols function, the first parameter must be a select function", __func__);
|
||||
goto _end;
|
||||
}
|
||||
int32_t selectFuncIndex = getSelectFuncIndex(*selectFuncList, pSelectFunc);
|
||||
if (selectFuncIndex == 0) {
|
||||
++selectFuncCount;
|
||||
selectFuncIndex = selectFuncCount;
|
||||
code = nodesCloneNode(pSelectFunc, &pNewNode);
|
||||
if(TSDB_CODE_SUCCESS != code) goto _end;
|
||||
((SExprNode*)pNewNode)->bindExprID = selectFuncIndex;
|
||||
code = nodesListMakeStrictAppend(selectFuncList, pNewNode);
|
||||
if(TSDB_CODE_SUCCESS != code) goto _end;
|
||||
}
|
||||
// start from index 1, because the first parameter is select function which needn't to output.
|
||||
for (int i = 1; i < pFunc->pParameterList->length; ++i) {
|
||||
SNode* pExpr = nodesListGetNode(pFunc->pParameterList, i);
|
||||
|
||||
code = nodesCloneNode(pExpr, &pNewNode);
|
||||
if(TSDB_CODE_SUCCESS != code) goto _end;
|
||||
if (nodesIsExprNode(pNewNode)) {
|
||||
SBindTupleFuncCxt pCxt = {pNewNode, selectFuncIndex};
|
||||
nodesRewriteExpr(&pNewNode, pushDownBindSelectFunc, &pCxt);
|
||||
} else {
|
||||
code = TSDB_CODE_PAR_INVALID_COLS_FUNCTION;
|
||||
parserError("%s Invalid cols function, the first parameter must be a select function", __func__);
|
||||
goto _end;
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS != code) goto _end;
|
||||
code = nodesListMakeStrictAppend(&pNewNodeList, pNewNode);
|
||||
if (TSDB_CODE_SUCCESS != code) goto _end;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
code = nodesCloneNode(pTmpNode, &pNewNode);
|
||||
if (TSDB_CODE_SUCCESS != code) goto _end;
|
||||
code = nodesListMakeStrictAppend(&pNewNodeList, pNewNode);
|
||||
if (TSDB_CODE_SUCCESS != code) goto _end;
|
||||
}
|
||||
nodesDestroyList(*nodeList);
|
||||
*nodeList = pNewNodeList;
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
_end:
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
nodesDestroyNode(pNewNode);
|
||||
nodesDestroyList(pNewNodeList);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t translateSelectFrom(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
pCxt->pCurrStmt = (SNode*)pSelect;
|
||||
|
|
|
@ -227,6 +227,10 @@ static char* getSyntaxErrFormat(int32_t errCode) {
|
|||
return "Some functions cannot appear in the select list at the same time";
|
||||
case TSDB_CODE_PAR_REGULAR_EXPRESSION_ERROR:
|
||||
return "Syntax error in regular expression";
|
||||
case TSDB_CODE_PAR_TRUE_FOR_NEGATIVE:
|
||||
return "True_for duration cannot be negative";
|
||||
case TSDB_CODE_PAR_TRUE_FOR_UNIT:
|
||||
return "Cannot use 'year' or 'month' as true_for duration";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ static EDealRes doRewriteExpr(SNode** pNode, void* pContext) {
|
|||
tstrncpy(pCol->node.userAlias, ((SExprNode*)pExpr)->userAlias, TSDB_COL_NAME_LEN);
|
||||
tstrncpy(pCol->colName, ((SExprNode*)pExpr)->aliasName, TSDB_COL_NAME_LEN);
|
||||
pCol->node.projIdx = ((SExprNode*)(*pNode))->projIdx;
|
||||
pCol->node.relatedTo = ((SExprNode*)(*pNode))->relatedTo;
|
||||
if (QUERY_NODE_FUNCTION == nodeType(pExpr)) {
|
||||
setColumnInfo((SFunctionNode*)pExpr, pCol, pCxt->isPartitionBy);
|
||||
}
|
||||
|
@ -150,7 +151,7 @@ static EDealRes doNameExpr(SNode* pNode, void* pContext) {
|
|||
case QUERY_NODE_LOGIC_CONDITION:
|
||||
case QUERY_NODE_FUNCTION: {
|
||||
if ('\0' == ((SExprNode*)pNode)->aliasName[0]) {
|
||||
snprintf(((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN, "#expr_%p", pNode);
|
||||
rewriteExprAliasName((SExprNode*)pNode, (int64_t)pNode);
|
||||
}
|
||||
return DEAL_RES_IGNORE_CHILD;
|
||||
}
|
||||
|
@ -757,6 +758,7 @@ static SColumnNode* createColumnByExpr(const char* pStmtName, SExprNode* pExpr)
|
|||
if (NULL != pStmtName) {
|
||||
snprintf(pCol->tableAlias, sizeof(pCol->tableAlias), "%s", pStmtName);
|
||||
}
|
||||
pCol->node.relatedTo = pExpr->relatedTo;
|
||||
return pCol;
|
||||
}
|
||||
|
||||
|
@ -1159,6 +1161,9 @@ static int32_t createWindowLogicNodeByState(SLogicPlanContext* pCxt, SStateWindo
|
|||
nodesDestroyNode((SNode*)pWindow);
|
||||
return code;
|
||||
}
|
||||
if (pState->pTrueForLimit) {
|
||||
pWindow->trueForLimit = ((SValueNode*)pState->pTrueForLimit)->datum.i;
|
||||
}
|
||||
// rewrite the expression in subsequent clauses
|
||||
code = rewriteExprForSelect(pWindow->pStateExpr, pSelect, SQL_CLAUSE_WINDOW);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
|
@ -1272,6 +1277,9 @@ static int32_t createWindowLogicNodeByEvent(SLogicPlanContext* pCxt, SEventWindo
|
|||
nodesDestroyNode((SNode*)pWindow);
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
if (pEvent->pTrueForLimit) {
|
||||
pWindow->trueForLimit = ((SValueNode*)pEvent->pTrueForLimit)->datum.i;
|
||||
}
|
||||
return createWindowLogicNodeFinalize(pCxt, pSelect, pWindow, pLogicNode);
|
||||
}
|
||||
|
||||
|
|
|
@ -3050,7 +3050,7 @@ static int32_t smaIndexOptCreateSmaCols(SNodeList* pFuncs, uint64_t tableId, SNo
|
|||
}
|
||||
SExprNode exprNode;
|
||||
exprNode.resType = ((SExprNode*)pWsNode)->resType;
|
||||
snprintf(exprNode.aliasName, TSDB_COL_NAME_LEN, "#expr_%d", index + 1);
|
||||
rewriteExprAliasName(&exprNode, index + 1);
|
||||
SColumnNode* pkNode = NULL;
|
||||
code = smaIndexOptCreateSmaCol((SNode*)&exprNode, tableId, PRIMARYKEY_TIMESTAMP_COL_ID, &pkNode);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "nodes.h"
|
||||
#include "planInt.h"
|
||||
|
||||
#include "catalog.h"
|
||||
|
@ -30,98 +31,82 @@ typedef struct SSlotIndex {
|
|||
SArray* pSlotIdsInfo; // duplicate name slot
|
||||
} SSlotIndex;
|
||||
|
||||
enum {
|
||||
SLOT_KEY_TYPE_ALL = 1,
|
||||
SLOT_KEY_TYPE_COLNAME = 2,
|
||||
};
|
||||
|
||||
static int32_t getSlotKeyHelper(SNode* pNode, const char* pPreName, const char* name, char** ppKey, int32_t callocLen,
|
||||
int32_t* pLen, uint16_t extraBufLen, int8_t slotKeyType) {
|
||||
int32_t code = 0;
|
||||
*ppKey = taosMemoryCalloc(1, callocLen);
|
||||
if (!*ppKey) {
|
||||
return terrno;
|
||||
}
|
||||
if (slotKeyType == SLOT_KEY_TYPE_ALL) {
|
||||
TAOS_STRNCAT(*ppKey, pPreName, TSDB_TABLE_NAME_LEN);
|
||||
TAOS_STRNCAT(*ppKey, ".", 2);
|
||||
TAOS_STRNCAT(*ppKey, name, TSDB_COL_NAME_LEN);
|
||||
*pLen = taosHashBinary(*ppKey, strlen(*ppKey));
|
||||
} else {
|
||||
TAOS_STRNCAT(*ppKey, name, TSDB_COL_NAME_LEN);
|
||||
*pLen = strlen(*ppKey);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t getSlotKey(SNode* pNode, const char* pStmtName, char** ppKey, int32_t* pLen, uint16_t extraBufLen) {
|
||||
int32_t code = 0;
|
||||
int32_t callocLen = 0;
|
||||
if (QUERY_NODE_COLUMN == nodeType(pNode)) {
|
||||
SColumnNode* pCol = (SColumnNode*)pNode;
|
||||
if (NULL != pStmtName) {
|
||||
if ('\0' != pStmtName[0]) {
|
||||
*ppKey = taosMemoryCalloc(1, TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen);
|
||||
if (!*ppKey) {
|
||||
return terrno;
|
||||
}
|
||||
TAOS_STRNCAT(*ppKey, pStmtName, TSDB_TABLE_NAME_LEN);
|
||||
TAOS_STRNCAT(*ppKey, ".", 2);
|
||||
TAOS_STRNCAT(*ppKey, pCol->node.aliasName, TSDB_COL_NAME_LEN);
|
||||
*pLen = taosHashBinary(*ppKey, strlen(*ppKey));
|
||||
return code;
|
||||
callocLen = TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen;
|
||||
return getSlotKeyHelper(pNode, pStmtName, pCol->node.aliasName, ppKey, callocLen, pLen, extraBufLen,
|
||||
SLOT_KEY_TYPE_ALL);
|
||||
} else {
|
||||
*ppKey = taosMemoryCalloc(1, TSDB_COL_NAME_LEN + 1 + extraBufLen);
|
||||
if (!*ppKey) {
|
||||
return terrno;
|
||||
}
|
||||
TAOS_STRNCAT(*ppKey, pCol->node.aliasName, TSDB_COL_NAME_LEN);
|
||||
*pLen = strlen(*ppKey);
|
||||
return code;
|
||||
callocLen = TSDB_COL_NAME_LEN + 1 + extraBufLen;
|
||||
return getSlotKeyHelper(pNode, pStmtName, pCol->node.aliasName, ppKey, callocLen, pLen, extraBufLen,
|
||||
SLOT_KEY_TYPE_COLNAME);
|
||||
}
|
||||
}
|
||||
if ('\0' == pCol->tableAlias[0]) {
|
||||
*ppKey = taosMemoryCalloc(1, TSDB_COL_NAME_LEN + 1 + extraBufLen);
|
||||
if (!*ppKey) {
|
||||
return terrno;
|
||||
callocLen = TSDB_COL_NAME_LEN + 1 + extraBufLen;
|
||||
return getSlotKeyHelper(pNode, pStmtName, pCol->colName, ppKey, callocLen, pLen, extraBufLen,
|
||||
SLOT_KEY_TYPE_COLNAME);
|
||||
}
|
||||
TAOS_STRNCAT(*ppKey, pCol->colName, TSDB_COL_NAME_LEN);
|
||||
*pLen = strlen(*ppKey);
|
||||
return code;
|
||||
}
|
||||
|
||||
*ppKey = taosMemoryCalloc(1, TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen);
|
||||
if (!*ppKey) {
|
||||
return terrno;
|
||||
}
|
||||
TAOS_STRNCAT(*ppKey, pCol->tableAlias, TSDB_TABLE_NAME_LEN);
|
||||
TAOS_STRNCAT(*ppKey, ".", 2);
|
||||
TAOS_STRNCAT(*ppKey, pCol->colName, TSDB_COL_NAME_LEN);
|
||||
*pLen = taosHashBinary(*ppKey, strlen(*ppKey));
|
||||
return code;
|
||||
callocLen = TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen;
|
||||
return getSlotKeyHelper(pNode, pCol->tableAlias, pCol->colName, ppKey, callocLen, pLen, extraBufLen,
|
||||
SLOT_KEY_TYPE_ALL);
|
||||
} else if (QUERY_NODE_FUNCTION == nodeType(pNode)) {
|
||||
SFunctionNode* pFunc = (SFunctionNode*)pNode;
|
||||
if (FUNCTION_TYPE_TBNAME == pFunc->funcType) {
|
||||
SValueNode* pVal = (SValueNode*)nodesListGetNode(pFunc->pParameterList, 0);
|
||||
if (pVal) {
|
||||
if (NULL != pStmtName && '\0' != pStmtName[0]) {
|
||||
*ppKey = taosMemoryCalloc(1, TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen);
|
||||
if (!*ppKey) {
|
||||
return terrno;
|
||||
}
|
||||
TAOS_STRNCAT(*ppKey, pStmtName, TSDB_TABLE_NAME_LEN);
|
||||
TAOS_STRNCAT(*ppKey, ".", 2);
|
||||
TAOS_STRNCAT(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN);
|
||||
*pLen = taosHashBinary(*ppKey, strlen(*ppKey));
|
||||
return code;
|
||||
callocLen = TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen;
|
||||
return getSlotKeyHelper(pNode, pStmtName, ((SExprNode*)pNode)->aliasName, ppKey, callocLen, pLen, extraBufLen,
|
||||
SLOT_KEY_TYPE_ALL);
|
||||
}
|
||||
int32_t literalLen = strlen(pVal->literal);
|
||||
*ppKey = taosMemoryCalloc(1, literalLen + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen);
|
||||
if (!*ppKey) {
|
||||
return terrno;
|
||||
}
|
||||
TAOS_STRNCAT(*ppKey, pVal->literal, literalLen);
|
||||
TAOS_STRNCAT(*ppKey, ".", 2);
|
||||
TAOS_STRNCAT(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN);
|
||||
*pLen = taosHashBinary(*ppKey, strlen(*ppKey));
|
||||
return code;
|
||||
callocLen = literalLen + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen;
|
||||
return getSlotKeyHelper(pNode, pVal->literal, ((SExprNode*)pNode)->aliasName, ppKey, callocLen, pLen,
|
||||
extraBufLen, SLOT_KEY_TYPE_ALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != pStmtName && '\0' != pStmtName[0]) {
|
||||
*ppKey = taosMemoryCalloc(1, TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen);
|
||||
if (!*ppKey) {
|
||||
return terrno;
|
||||
}
|
||||
TAOS_STRNCAT(*ppKey, pStmtName, TSDB_TABLE_NAME_LEN);
|
||||
TAOS_STRNCAT(*ppKey, ".", 2);
|
||||
TAOS_STRNCAT(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN);
|
||||
*pLen = taosHashBinary(*ppKey, strlen(*ppKey));
|
||||
return code;
|
||||
callocLen = TSDB_TABLE_NAME_LEN + 1 + TSDB_COL_NAME_LEN + 1 + extraBufLen;
|
||||
return getSlotKeyHelper(pNode, pStmtName, ((SExprNode*)pNode)->aliasName, ppKey, callocLen, pLen, extraBufLen,
|
||||
SLOT_KEY_TYPE_ALL);
|
||||
}
|
||||
|
||||
*ppKey = taosMemoryCalloc(1, TSDB_COL_NAME_LEN + 1 + extraBufLen);
|
||||
if (!*ppKey) {
|
||||
return terrno;
|
||||
}
|
||||
TAOS_STRNCAT(*ppKey, ((SExprNode*)pNode)->aliasName, TSDB_COL_NAME_LEN);
|
||||
*pLen = strlen(*ppKey);
|
||||
callocLen = TSDB_COL_NAME_LEN + 1 + extraBufLen;
|
||||
return getSlotKeyHelper(pNode, pStmtName, ((SExprNode*)pNode)->aliasName, ppKey, callocLen, pLen, extraBufLen,
|
||||
SLOT_KEY_TYPE_COLNAME);
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -2328,6 +2313,8 @@ static int32_t createStateWindowPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pC
|
|||
// }
|
||||
}
|
||||
|
||||
pState->trueForLimit = pWindowLogicNode->trueForLimit;
|
||||
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = createWindowPhysiNodeFinalize(pCxt, pChildren, &pState->window, pWindowLogicNode);
|
||||
}
|
||||
|
@ -2358,6 +2345,7 @@ static int32_t createEventWindowPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pC
|
|||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = setNodeSlotId(pCxt, pChildTupe->dataBlockId, -1, pWindowLogicNode->pEndCond, &pEvent->pEndCond);
|
||||
}
|
||||
pEvent->trueForLimit = pWindowLogicNode->trueForLimit;
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = createWindowPhysiNodeFinalize(pCxt, pChildren, &pEvent->window, pWindowLogicNode);
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ static EDealRes doCreateColumn(SNode* pNode, void* pContext) {
|
|||
}
|
||||
}
|
||||
}
|
||||
pCol->node.relatedTo = pExpr->relatedTo;
|
||||
return (TSDB_CODE_SUCCESS == nodesListStrictAppend(pCxt->pList, (SNode*)pCol) ? DEAL_RES_IGNORE_CHILD
|
||||
: DEAL_RES_ERROR);
|
||||
}
|
||||
|
|
|
@ -4402,3 +4402,4 @@ int32_t uniqueScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarPara
|
|||
int32_t modeScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput) {
|
||||
return selectScalarFunction(pInput, inputNum, pOutput);
|
||||
}
|
||||
|
||||
|
|
|
@ -1347,9 +1347,6 @@ int64_t taosGetLineFile(TdFilePtr pFile, char **__restrict ptrBuf) {
|
|||
int64_t ret = -1;
|
||||
int32_t code = 0;
|
||||
|
||||
#if FILE_WITH_LOCK
|
||||
(void)taosThreadRwlockRdlock(&(pFile->rwlock));
|
||||
#endif
|
||||
if (pFile == NULL || ptrBuf == NULL) {
|
||||
terrno = TSDB_CODE_INVALID_PARA;
|
||||
goto END;
|
||||
|
@ -1363,6 +1360,10 @@ int64_t taosGetLineFile(TdFilePtr pFile, char **__restrict ptrBuf) {
|
|||
goto END;
|
||||
}
|
||||
|
||||
#if FILE_WITH_LOCK
|
||||
(void)taosThreadRwlockRdlock(&(pFile->rwlock));
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS
|
||||
size_t bufferSize = 512;
|
||||
*ptrBuf = taosMemoryMalloc(bufferSize);
|
||||
|
@ -1619,10 +1620,12 @@ size_t taosReadFromCFile(void *buffer, size_t size, size_t count, FILE *stream)
|
|||
return fread(buffer, size, count, stream);
|
||||
}
|
||||
|
||||
#if 0
|
||||
size_t taosWriteToCFile(const void *ptr, size_t size, size_t nitems, FILE *stream) {
|
||||
STUB_RAND_IO_ERR(terrno)
|
||||
return fwrite(ptr, size, nitems, stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
int taosCloseCFile(FILE *f) { return fclose(f); }
|
||||
|
||||
|
|
|
@ -30,6 +30,12 @@ add_test(
|
|||
NAME osDirTests
|
||||
COMMAND osDirTests
|
||||
)
|
||||
add_executable(osFileTests "osFileTests.cpp")
|
||||
target_link_libraries(osFileTests os util gtest_main)
|
||||
add_test(
|
||||
NAME osFileTests
|
||||
COMMAND osFileTests
|
||||
)
|
||||
endif()
|
||||
|
||||
if(TD_LINUX)
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <iostream>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wwrite-strings"
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
#pragma GCC diagnostic ignored "-Wformat"
|
||||
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
|
||||
#pragma GCC diagnostic ignored "-Wpointer-arith"
|
||||
|
||||
#include "os.h"
|
||||
#include "tlog.h"
|
||||
|
||||
TEST(osFileTests, taosGetTmpfilePath) {
|
||||
char inputTmpDir[100] = "/tmp";
|
||||
char fileNamePrefix[100] = "txt";
|
||||
char dstPath[100] = {0};
|
||||
|
||||
taosGetTmpfilePath(NULL, fileNamePrefix, dstPath);
|
||||
taosGetTmpfilePath(inputTmpDir, NULL, dstPath);
|
||||
taosGetTmpfilePath(inputTmpDir, fileNamePrefix, dstPath);
|
||||
|
||||
int32_t ret = taosRemoveFile(NULL);
|
||||
EXPECT_NE(ret, 0);
|
||||
|
||||
ret = taosCloseFile(NULL);
|
||||
EXPECT_EQ(ret, 0);
|
||||
|
||||
ret = taosRenameFile(NULL, "");
|
||||
EXPECT_NE(ret, 0);
|
||||
ret = taosRenameFile("", NULL);
|
||||
EXPECT_NE(ret, 0);
|
||||
|
||||
int64_t stDev = 0;
|
||||
int64_t stIno = 0;
|
||||
ret = taosDevInoFile(NULL, &stDev, &stIno);
|
||||
EXPECT_NE(ret, 0);
|
||||
}
|
||||
|
||||
TEST(osFileTests, taosCopyFile) {
|
||||
char from[100] = {0};
|
||||
char to[100] = {0};
|
||||
int64_t ret = taosCopyFile(from, NULL);
|
||||
EXPECT_EQ(ret, -1);
|
||||
|
||||
ret = taosCopyFile(NULL, to);
|
||||
EXPECT_EQ(ret, -1);
|
||||
|
||||
ret = taosCopyFile(from, to);
|
||||
EXPECT_EQ(ret, -1);
|
||||
|
||||
tstrncpy(from, "/tmp/tdengine-test-file", sizeof(from));
|
||||
TdFilePtr testFilePtr = taosCreateFile(from, TD_FILE_CREATE);
|
||||
taosWriteFile(testFilePtr, "abcdefg", 9);
|
||||
|
||||
int64_t ret64 = taosReadFile(testFilePtr, NULL, 0);
|
||||
EXPECT_NE(ret64, 0);
|
||||
ret64 = taosReadFile(NULL, to, 100);
|
||||
EXPECT_NE(ret64, 0);
|
||||
ret64 = taosWriteFile(testFilePtr, NULL, 0);
|
||||
EXPECT_EQ(ret64, 0);
|
||||
ret64 = taosWriteFile(NULL, to, 100);
|
||||
EXPECT_EQ(ret64, 0);
|
||||
ret64 = taosPWriteFile(testFilePtr, NULL, 0, 0);
|
||||
EXPECT_EQ(ret64, 0);
|
||||
ret64 = taosPWriteFile(NULL, to, 100, 0);
|
||||
EXPECT_EQ(ret64, 0);
|
||||
ret64 = taosLSeekFile(NULL, 0, 0);
|
||||
EXPECT_EQ(ret64, -1);
|
||||
|
||||
ret64 = taosPReadFile(NULL, NULL, 0, 0);
|
||||
EXPECT_EQ(ret64, -1);
|
||||
|
||||
bool retb = taosValidFile(testFilePtr);
|
||||
EXPECT_TRUE(retb);
|
||||
retb = taosValidFile(NULL);
|
||||
EXPECT_FALSE(retb);
|
||||
|
||||
retb = taosCheckAccessFile(NULL, 0);
|
||||
EXPECT_FALSE(retb);
|
||||
|
||||
int32_t ret32 = taosFStatFile(NULL, NULL, NULL);
|
||||
EXPECT_NE(ret32, 0);
|
||||
|
||||
ret32 = taosLockFile(NULL);
|
||||
EXPECT_NE(ret32, 0);
|
||||
ret32 = taosUnLockFile(NULL);
|
||||
EXPECT_NE(ret32, 0);
|
||||
ret32 = taosFtruncateFile(NULL, 0);
|
||||
EXPECT_NE(ret32, 0);
|
||||
ret64 = taosFSendFile(NULL, testFilePtr, NULL, 0);
|
||||
EXPECT_NE(ret64, 0);
|
||||
ret64 = taosFSendFile(testFilePtr, NULL, NULL, 0);
|
||||
EXPECT_NE(ret64, 0);
|
||||
|
||||
char buf[100] = {0};
|
||||
ret64 = taosGetLineFile(NULL, (char**)&buf);
|
||||
EXPECT_EQ(ret64, -1);
|
||||
ret64 = taosGetLineFile(testFilePtr, NULL);
|
||||
EXPECT_EQ(ret64, -1);
|
||||
|
||||
ret64 = taosGetsFile(testFilePtr, 0, NULL);
|
||||
EXPECT_NE(ret64, -1);
|
||||
ret64 = taosGetsFile(NULL, 0, buf);
|
||||
EXPECT_NE(ret64, -1);
|
||||
|
||||
ret32 = taosEOFFile(NULL);
|
||||
EXPECT_NE(ret64, -1);
|
||||
|
||||
taosCloseFile(&testFilePtr);
|
||||
ret32 = taosFStatFile(testFilePtr, NULL, NULL);
|
||||
EXPECT_NE(ret32, 0);
|
||||
ret32 = taosLockFile(testFilePtr);
|
||||
EXPECT_NE(ret32, 0);
|
||||
ret32 = taosUnLockFile(testFilePtr);
|
||||
EXPECT_NE(ret32, 0);
|
||||
ret32 = taosFtruncateFile(testFilePtr, 0);
|
||||
EXPECT_NE(ret32, 0);
|
||||
ret64 = taosFSendFile(testFilePtr, testFilePtr, NULL, 0);
|
||||
EXPECT_NE(ret64, 0);
|
||||
ret64 = taosGetLineFile(testFilePtr, NULL);
|
||||
EXPECT_EQ(ret64, -1);
|
||||
ret64 = taosGetsFile(testFilePtr, 0, NULL);
|
||||
EXPECT_NE(ret64, -1);
|
||||
ret32 = taosEOFFile(testFilePtr);
|
||||
EXPECT_NE(ret64, -1);
|
||||
|
||||
retb = taosValidFile(testFilePtr);
|
||||
EXPECT_FALSE(retb);
|
||||
|
||||
ret = taosCopyFile(from, to);
|
||||
EXPECT_EQ(ret, -1);
|
||||
|
||||
int64_t size = 0;
|
||||
int64_t mtime = 0;
|
||||
int64_t atime = 0;
|
||||
ret = taosStatFile(NULL, &size, &mtime, &atime);
|
||||
EXPECT_NE(ret, 0);
|
||||
|
||||
ret = taosStatFile(from, &size, &mtime, NULL);
|
||||
EXPECT_EQ(ret, 0);
|
||||
|
||||
int64_t diskid = 0;
|
||||
ret = taosGetFileDiskID(NULL, &diskid);
|
||||
EXPECT_NE(ret, 0);
|
||||
|
||||
ret = taosGetFileDiskID("", &diskid);
|
||||
EXPECT_NE(ret, 0);
|
||||
|
||||
ret = taosGetFileDiskID(from, NULL);
|
||||
EXPECT_EQ(ret, 0);
|
||||
|
||||
ret32 = taosCompressFile(NULL, "");
|
||||
EXPECT_NE(ret32, 0);
|
||||
ret32 = taosCompressFile("", NULL);
|
||||
EXPECT_NE(ret32, 0);
|
||||
ret32 = taosCompressFile("", "");
|
||||
EXPECT_NE(ret32, 0);
|
||||
ret32 = taosCompressFile("/tmp/tdengine-test-file", "");
|
||||
EXPECT_NE(ret32, 0);
|
||||
|
||||
ret32 = taosLinkFile("", "");
|
||||
EXPECT_NE(ret32, 0);
|
||||
|
||||
char mod[8] = {0};
|
||||
FILE* retptr = taosOpenCFile(NULL, "");
|
||||
EXPECT_EQ(retptr, nullptr);
|
||||
retptr = taosOpenCFile("", NULL);
|
||||
EXPECT_EQ(retptr, nullptr);
|
||||
retptr = taosOpenCFile("", mod);
|
||||
EXPECT_EQ(retptr, nullptr);
|
||||
|
||||
ret32 = taosSeekCFile(NULL, 0, 0);
|
||||
EXPECT_NE(ret32, 0);
|
||||
|
||||
size_t retsize = taosReadFromCFile(buf, 0, 0, NULL);
|
||||
EXPECT_EQ(retsize, 0);
|
||||
retsize = taosReadFromCFile(NULL, 0, 0, NULL);
|
||||
EXPECT_EQ(retsize, 0);
|
||||
|
||||
taosRemoveFile(from);
|
||||
}
|
||||
|
||||
TEST(osFileTests, taosCreateFile) {
|
||||
char path[100] = {0};
|
||||
int32_t tdFileOptions = 0;
|
||||
|
||||
TdFilePtr ret = taosCreateFile(NULL, 0);
|
||||
EXPECT_EQ(ret, nullptr);
|
||||
|
||||
ret = taosCreateFile(path, 0);
|
||||
EXPECT_EQ(ret, nullptr);
|
||||
|
||||
FILE* retptr = taosOpenFileForStream(NULL, 0);
|
||||
EXPECT_EQ(retptr, nullptr);
|
||||
|
||||
TdFilePtr retptr2 = taosOpenFile(NULL, 0);
|
||||
EXPECT_EQ(retptr2, nullptr);
|
||||
}
|
|
@ -752,6 +752,13 @@ TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_ANOMALY_WIN_OPT, "ANOMALY_WINDOW opti
|
|||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_FORECAST_CLAUSE, "Invalid forecast clause")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_REGULAR_EXPRESSION_ERROR, "Syntax error in regular expression")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_VGID_LIST, "Invalid vgid list")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_TRUE_FOR_NEGATIVE, "True_for duration cannot be negative")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_TRUE_FOR_UNIT, "Cannot use 'year' or 'month' as true_for duration")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_COLS_FUNCTION, "Invalid cols function")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_COLS_SELECTFUNC, "cols function's first param must be a select function that output a single row")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_INVALID_MULITI_COLS_FUNC, "Improper use of cols function with multiple output columns")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_INVALID_COLS_ALIAS, "Invalid using alias for cols function")
|
||||
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INTERNAL_ERROR, "Parser internal error")
|
||||
|
||||
//planner
|
||||
|
|
|
@ -554,6 +554,8 @@ TSDB_CODE_PAR_COL_PK_TYPE = 0x80002679
|
|||
TSDB_CODE_PAR_INVALID_PK_OP = 0x8000267A
|
||||
TSDB_CODE_PAR_PRIMARY_KEY_IS_NULL = 0x8000267B
|
||||
TSDB_CODE_PAR_PRIMARY_KEY_IS_NONE = 0x8000267C
|
||||
TSDB_CODE_PAR_TRUE_FOR_NEGATIVE = 0x80002687
|
||||
TSDB_CODE_PAR_TRUE_FOR_UNIT = 0x80002688
|
||||
TSDB_CODE_PAR_INTERNAL_ERROR = 0x800026FF
|
||||
TSDB_CODE_PLAN_INTERNAL_ERROR = 0x80002700
|
||||
TSDB_CODE_PLAN_EXPECTED_TS_EQUAL = 0x80002701
|
||||
|
|
|
@ -1260,6 +1260,10 @@
|
|||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/odbc.py
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/fill_with_group.py
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/state_window.py -Q 3
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/cols_function.py
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/cols_function.py -Q 2
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/cols_function.py -Q 3
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/cols_function.py -Q 4
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 99-TDcase/TD-21561.py -Q 4
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 99-TDcase/TD-20582.py
|
||||
,,n,system-test,python3 ./test.py -f eco-system/meta/database/keep_time_offset.py
|
||||
|
@ -1268,6 +1272,7 @@
|
|||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/operator.py -Q 3
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/operator.py -Q 4
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f eco-system/manager/schema_change.py -N 3 -M 3
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/test_window_true_for.py
|
||||
|
||||
#tsim test
|
||||
,,y,script,./test.sh -f tsim/query/timeline.sim
|
||||
|
|
|
@ -672,6 +672,15 @@ class TDSql:
|
|||
args = (caller.filename, caller.lineno, self.sql, col_name_list, expect_col_name_list)
|
||||
tdLog.exit("%s(%d) failed: sql:%s, col_name_list:%s != expect_col_name_list:%s" % args)
|
||||
|
||||
def checkResColNameList(self, expect_col_name_list):
|
||||
col_name_list = []
|
||||
col_type_list = []
|
||||
for query_col in self.cursor.description:
|
||||
col_name_list.append(query_col[0])
|
||||
col_type_list.append(query_col[1])
|
||||
|
||||
self.checkColNameList(col_name_list, expect_col_name_list)
|
||||
|
||||
def __check_equal(self, elm, expect_elm):
|
||||
if elm == expect_elm:
|
||||
return True
|
||||
|
|
|
@ -15,3 +15,5 @@ TSDB_CODE_UDF_FUNC_EXEC_FAILURE = (TAOS_DEF_ERROR_CODE | 0x290A)
|
|||
TSDB_CODE_TSC_INTERNAL_ERROR = (TAOS_DEF_ERROR_CODE | 0x02FF)
|
||||
|
||||
TSDB_CODE_PAR_SYNTAX_ERROR = (TAOS_DEF_ERROR_CODE | 0x2600)
|
||||
|
||||
TSDB_CODE_PAR_INVALID_COLS_FUNCTION = (TAOS_DEF_ERROR_CODE | 0x2687)
|
||||
|
|
|
@ -1294,7 +1294,10 @@ sql_error select avg(f1), spread(f1), spread(f2), spread(tb1.f1) from tb1 group
|
|||
|
||||
sql_error select avg(f1), spread(f1), spread(f2), spread(tb1.f1) from tb1 group by f1 having spread(f1) > id1 and sum(f1);
|
||||
|
||||
sql_error select avg(f1), spread(f1), spread(f2), spread(tb1.f1) from tb1 group by f1 having spread(f1) > id1 and sum(f1) > 1;
|
||||
sql select avg(f1), spread(f1), spread(f2), spread(tb1.f1) from tb1 group by f1 having spread(f1) > id1 and sum(f1) > 1;
|
||||
if $rows != 0 then
|
||||
return -1
|
||||
endi
|
||||
|
||||
sql select avg(f1), spread(f1), spread(f2), spread(tb1.f1) from tb1 group by f1 having spread(f1) > 2 and sum(f1) > 1 order by f1;
|
||||
if $rows != 0 then
|
||||
|
|
|
@ -809,7 +809,6 @@ sql create stable st(ts timestamp, a int, b int , c int) tags(ta int,tb int,tc i
|
|||
sql create table ts1 using st tags(1,1,1);
|
||||
sql create stream streams5 trigger at_once IGNORE EXPIRED 0 IGNORE UPDATE 0 into streamt5 as select count(*), _wstart, _wend, max(a) from ts1 interval(10s) ;
|
||||
sql create stream streams6 trigger at_once IGNORE EXPIRED 0 IGNORE UPDATE 0 into streamt6 as select count(*), _wstart, _wend, max(a), _wstart as ts from ts1 interval(10s) ;
|
||||
|
||||
run tsim/stream/checkTaskStatus.sim
|
||||
|
||||
sql_error create stream streams7 trigger at_once into streamt7 as select _wstart, count(*), _wstart, _wend, max(a) from ts1 interval(10s) ;
|
||||
|
@ -833,14 +832,14 @@ if $loop_count == 10 then
|
|||
endi
|
||||
|
||||
if $rows != 1 then
|
||||
print =====rows=$rows
|
||||
print ===== streamt5: rows=$rows
|
||||
goto loop170
|
||||
endi
|
||||
|
||||
sql select * from streamt6;
|
||||
|
||||
if $rows != 1 then
|
||||
print =====rows=$rows
|
||||
print ===== streamt6: rows=$rows
|
||||
goto loop170
|
||||
endi
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -295,7 +295,7 @@ class TDTestCase:
|
|||
tdSql.query("select last(ts) from meters partition by tbname")
|
||||
tdSql.query("select last(ts) from meters partition by t1")
|
||||
sql_template = 'select %s from meters partition by tbname'
|
||||
select_items = ["ts, last(c10), c10, ts", "ts, ts, last(c10), c10, tbname", "last(c10), c10, ts"]
|
||||
select_items = ["ts, last(c10), c10, ts", "ts, ts, last(c10), c10, tbname", "last(c10), c10, ts", "ts, ts, last(c10), c10, t1" ]
|
||||
has_last_row_scan_res = [1,1,1]
|
||||
sqls = self.format_sqls(sql_template, select_items)
|
||||
self.explain_and_check_res(sqls, has_last_row_scan_res)
|
||||
|
@ -313,6 +313,13 @@ class TDTestCase:
|
|||
tdSql.checkData(0,2, '2018-11-25 19:30:01.000')
|
||||
tdSql.checkData(0,3, '2018-11-25 19:30:01.000')
|
||||
|
||||
tdSql.query(sqls[3], queryTimes=1)
|
||||
tdSql.checkRows(10)
|
||||
tdSql.checkData(0,0, '2018-11-25 19:30:00.000')
|
||||
tdSql.checkData(0,1, '2018-11-25 19:30:00.000')
|
||||
tdSql.checkData(0,2, '2018-11-25 19:30:01.000')
|
||||
tdSql.checkData(0,3, '2018-11-25 19:30:01.000')
|
||||
|
||||
sql_template = 'select %s from meters partition by t1'
|
||||
select_items = ["ts, last(c10), c10, ts", "ts, ts, last(c10), c10, t1", "last(c10), c10, ts"]
|
||||
has_last_row_scan_res = [1,1,1]
|
||||
|
|
|
@ -0,0 +1,488 @@
|
|||
###################################################################
|
||||
# Copyright (c) 2016 by TAOS Technologies, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is proprietary and confidential to TAOS Technologies.
|
||||
# No part of this file may be reproduced, stored, transmitted,
|
||||
# disclosed or used in any form or by any means other than as
|
||||
# expressly provided by the written permission from Jianhui Tao
|
||||
#
|
||||
###################################################################
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
import taos
|
||||
from util.log import *
|
||||
from util.cases import *
|
||||
from util.sql import *
|
||||
|
||||
class TDTestCase:
|
||||
# init
|
||||
def init(self, conn, logSql, replicaVar=1):
|
||||
self.replicaVar = int(replicaVar)
|
||||
tdLog.debug(f"start to excute {__file__}")
|
||||
tdSql.init(conn.cursor(), True)
|
||||
|
||||
def create_objects(self):
|
||||
tdSql.execute("drop database if exists test", show=True)
|
||||
tdSql.execute("create database test keep 36500 precision 'ms'", show=True)
|
||||
tdSql.execute("use test", show=True)
|
||||
tdSql.execute("create stable st (ts timestamp, c1 int) tags (gid int)", show=True)
|
||||
tdSql.execute("create table ct_0 using st(gid) tags (0)")
|
||||
tdSql.execute("create table ct_1 using st(gid) tags (1)")
|
||||
|
||||
tdSql.execute(f'''create stream s_event_1 into d_event_1 as
|
||||
select _wstart, _wend, count(*) from ct_0
|
||||
event_window start with c1 > 0 end with c1 < 0 true_for(3s);''', show=True)
|
||||
tdSql.execute(f'''create stream s_event_2 ignore update 0 ignore expired 0 into d_event_2 as
|
||||
select _wstart, _wend, count(*) from ct_0
|
||||
event_window start with c1 > 0 end with c1 < 0 true_for(3s);''', show=True)
|
||||
|
||||
tdSql.execute(f'''create stream s_event_3 into d_event_3 as
|
||||
select _wstart, _wend, count(*) from ct_0
|
||||
event_window start with c1 > 0 end with c1 < 0 true_for(2999);''', show=True)
|
||||
tdSql.execute(f'''create stream s_event_4 ignore update 0 ignore expired 0 into d_event_4 as
|
||||
select _wstart, _wend, count(*) from ct_0
|
||||
event_window start with c1 > 0 end with c1 < 0 true_for(2999);''', show=True)
|
||||
|
||||
tdSql.execute(f'''create stream s_event_5 into d_event_5 as
|
||||
select _wstart, _wend, count(*) from ct_0
|
||||
event_window start with c1 > 0 end with c1 < 0 true_for('3001a');''', show=True)
|
||||
tdSql.execute(f'''create stream s_event_6 ignore update 0 ignore expired 0 into d_event_6 as
|
||||
select _wstart, _wend, count(*) from ct_0
|
||||
event_window start with c1 > 0 end with c1 < 0 true_for('3001a');''', show=True)
|
||||
|
||||
tdSql.execute(f'''create stream s_state_1 into d_state_1 as
|
||||
select _wstart, _wend, count(*) from ct_1
|
||||
state_window(c1) true_for (3s);''', show=True)
|
||||
tdSql.execute(f'''create stream s_state_2 ignore update 0 ignore expired 0 into d_state_2 as
|
||||
select _wstart, _wend, count(*) from ct_1
|
||||
state_window(c1) true_for (3s);''', show=True)
|
||||
|
||||
tdSql.execute(f'''create stream s_state_3 into d_state_3 as
|
||||
select _wstart, _wend, count(*) from ct_1
|
||||
state_window(c1) true_for (2999);''', show=True)
|
||||
tdSql.execute(f'''create stream s_state_4 ignore update 0 ignore expired 0 into d_state_4 as
|
||||
select _wstart, _wend, count(*) from ct_1
|
||||
state_window(c1) true_for (2999);''', show=True)
|
||||
|
||||
tdSql.execute(f'''create stream s_state_5 into d_state_5 as
|
||||
select _wstart, _wend, count(*) from ct_1
|
||||
state_window(c1) true_for ('3001a');''', show=True)
|
||||
tdSql.execute(f'''create stream s_state_6 ignore update 0 ignore expired 0 into d_state_6 as
|
||||
select _wstart, _wend, count(*) from ct_1
|
||||
state_window(c1) true_for ('3001a');''', show=True)
|
||||
# Wait for the stream tasks to be ready
|
||||
for i in range(50):
|
||||
tdLog.info(f"i={i} wait for stream tasks ready ...")
|
||||
time.sleep(1)
|
||||
rows = tdSql.query("select * from information_schema.ins_stream_tasks where status <> 'ready';")
|
||||
if rows == 0:
|
||||
break
|
||||
|
||||
def insert_data(self):
|
||||
tdSql.execute(f'''insert into ct_0 values
|
||||
('2025-01-01 00:00:00.000', -1),
|
||||
('2025-01-01 00:00:01.000', 1),
|
||||
('2025-01-01 00:00:02.000', -1),
|
||||
('2025-01-01 00:00:03.000', 1),
|
||||
('2025-01-01 00:00:04.000', 1),
|
||||
('2025-01-01 00:00:05.000', -1),
|
||||
('2025-01-01 00:00:06.000', 1),
|
||||
('2025-01-01 00:00:07.000', 1),
|
||||
('2025-01-01 00:00:08.000', 1),
|
||||
('2025-01-01 00:00:08.999', -1),
|
||||
('2025-01-01 00:00:10.000', 1),
|
||||
('2025-01-01 00:00:11.000', 1),
|
||||
('2025-01-01 00:00:12.000', 1),
|
||||
('2025-01-01 00:00:13.000', -1),
|
||||
('2025-01-01 00:00:14.000', 1),
|
||||
('2025-01-01 00:00:15.000', 1),
|
||||
('2025-01-01 00:00:16.000', 1),
|
||||
('2025-01-01 00:00:17.001', -1),
|
||||
('2025-01-01 00:00:18.000', 1),
|
||||
('2025-01-01 00:00:19.000', 1),
|
||||
('2025-01-01 00:00:20.000', 1),
|
||||
('2025-01-01 00:00:21.000', 1),
|
||||
('2025-01-01 00:00:22.000', -1),
|
||||
('2025-01-01 00:00:23.000', -1),
|
||||
('2025-01-01 00:00:24.000', 1),
|
||||
('2025-01-01 00:00:25.000', 1),
|
||||
('2025-01-01 00:00:26.000', 1),
|
||||
('2025-01-01 00:00:27.000', 1),
|
||||
('2025-01-01 00:00:28.000', 1),
|
||||
('2025-01-01 00:00:29.000', 1),
|
||||
('2025-01-01 00:00:30.000', -1),
|
||||
('2025-01-01 00:00:31.000', 0);''', show=True)
|
||||
tdSql.execute(f'''insert into ct_1 values
|
||||
('2025-01-01 00:00:00.000', 0),
|
||||
('2025-01-01 00:00:01.000', 1),
|
||||
('2025-01-01 00:00:02.000', 1),
|
||||
('2025-01-01 00:00:03.000', 2),
|
||||
('2025-01-01 00:00:04.000', 2),
|
||||
('2025-01-01 00:00:05.000', 2),
|
||||
('2025-01-01 00:00:06.000', 3),
|
||||
('2025-01-01 00:00:07.000', 3),
|
||||
('2025-01-01 00:00:08.000', 3),
|
||||
('2025-01-01 00:00:08.999', 3),
|
||||
('2025-01-01 00:00:10.000', 4),
|
||||
('2025-01-01 00:00:11.000', 4),
|
||||
('2025-01-01 00:00:12.000', 4),
|
||||
('2025-01-01 00:00:13.000', 4),
|
||||
('2025-01-01 00:00:14.000', 5),
|
||||
('2025-01-01 00:00:15.000', 5),
|
||||
('2025-01-01 00:00:16.000', 5),
|
||||
('2025-01-01 00:00:17.001', 5),
|
||||
('2025-01-01 00:00:18.000', 6),
|
||||
('2025-01-01 00:00:19.000', 6),
|
||||
('2025-01-01 00:00:20.000', 6),
|
||||
('2025-01-01 00:00:21.000', 6),
|
||||
('2025-01-01 00:00:22.000', 6),
|
||||
('2025-01-01 00:00:23.000', 0),
|
||||
('2025-01-01 00:00:24.000', 7),
|
||||
('2025-01-01 00:00:25.000', 7),
|
||||
('2025-01-01 00:00:26.000', 7),
|
||||
('2025-01-01 00:00:27.000', 7),
|
||||
('2025-01-01 00:00:28.000', 7),
|
||||
('2025-01-01 00:00:29.000', 7),
|
||||
('2025-01-01 00:00:30.000', 7),
|
||||
('2025-01-01 00:00:31.000', 0);''', show=True)
|
||||
tdLog.info("wait for all stream tasks to be ready ...")
|
||||
time.sleep(10)
|
||||
|
||||
def update_data(self):
|
||||
tdSql.execute(f'''insert into ct_0 values
|
||||
('2025-01-01 00:00:00.000', 1),
|
||||
('2025-01-01 00:00:22.000', 1),
|
||||
('2025-01-01 00:00:28.000', -1);''', show=True)
|
||||
tdSql.execute(f'''insert into ct_1 values
|
||||
('2025-01-01 00:00:00.000', 1),
|
||||
('2025-01-01 00:00:23.000', 6),
|
||||
('2025-01-01 00:00:29.000', 8),
|
||||
('2025-01-01 00:00:30.000', 8);''', show=True)
|
||||
tdLog.info("wait for all stream tasks to be ready ...")
|
||||
time.sleep(5)
|
||||
|
||||
def check_result(self):
|
||||
tdSql.query("select * from d_event_1", show=True)
|
||||
tdSql.checkRows(4)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:10.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:13.000')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(1, 2, 4)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:22.000')
|
||||
tdSql.checkData(2, 2, 5)
|
||||
tdSql.checkData(3, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(3, 1, '2025-01-01 00:00:30.000')
|
||||
tdSql.checkData(3, 2, 7)
|
||||
|
||||
tdSql.query("select * from d_event_2", show=True)
|
||||
tdSql.checkRows(4)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:10.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:13.000')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(1, 2, 4)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:23.000')
|
||||
tdSql.checkData(2, 2, 6)
|
||||
tdSql.checkData(3, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(3, 1, '2025-01-01 00:00:28.000')
|
||||
tdSql.checkData(3, 2, 5)
|
||||
|
||||
tdSql.query("select _wstart, _wend, count(*) from ct_0 event_window start with c1 > 0 end with c1 < 0 true_for(3s);", show=True)
|
||||
tdSql.checkRows(4)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:10.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:13.000')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(1, 2, 4)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:23.000')
|
||||
tdSql.checkData(2, 2, 6)
|
||||
tdSql.checkData(3, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(3, 1, '2025-01-01 00:00:28.000')
|
||||
tdSql.checkData(3, 2, 5)
|
||||
|
||||
tdSql.query("select * from d_event_3", show=True)
|
||||
tdSql.checkRows(5)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:06.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:08.999')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:10.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:13.000')
|
||||
tdSql.checkData(1, 2, 4)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(2, 2, 4)
|
||||
tdSql.checkData(3, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(3, 1, '2025-01-01 00:00:22.000')
|
||||
tdSql.checkData(3, 2, 5)
|
||||
tdSql.checkData(4, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(4, 1, '2025-01-01 00:00:30.000')
|
||||
tdSql.checkData(4, 2, 7)
|
||||
|
||||
tdSql.query("select * from d_event_4", show=True)
|
||||
tdSql.checkRows(5)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:06.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:08.999')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:10.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:13.000')
|
||||
tdSql.checkData(1, 2, 4)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(2, 2, 4)
|
||||
tdSql.checkData(3, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(3, 1, '2025-01-01 00:00:23.000')
|
||||
tdSql.checkData(3, 2, 6)
|
||||
tdSql.checkData(4, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(4, 1, '2025-01-01 00:00:28.000')
|
||||
tdSql.checkData(4, 2, 5)
|
||||
|
||||
tdSql.query("select _wstart, _wend, count(*) from ct_0 event_window start with c1 > 0 end with c1 < 0 true_for(2999);", show=True)
|
||||
tdSql.checkRows(5)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:06.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:08.999')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:10.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:13.000')
|
||||
tdSql.checkData(1, 2, 4)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(2, 2, 4)
|
||||
tdSql.checkData(3, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(3, 1, '2025-01-01 00:00:23.000')
|
||||
tdSql.checkData(3, 2, 6)
|
||||
tdSql.checkData(4, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(4, 1, '2025-01-01 00:00:28.000')
|
||||
tdSql.checkData(4, 2, 5)
|
||||
|
||||
tdSql.query("select * from d_event_5", show=True)
|
||||
tdSql.checkRows(3)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:22.000')
|
||||
tdSql.checkData(1, 2, 5)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:30.000')
|
||||
tdSql.checkData(2, 2, 7)
|
||||
|
||||
tdSql.query("select * from d_event_6", show=True)
|
||||
tdSql.checkRows(3)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:23.000')
|
||||
tdSql.checkData(1, 2, 6)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:28.000')
|
||||
tdSql.checkData(2, 2, 5)
|
||||
|
||||
tdSql.query("select _wstart, _wend, count(*) from ct_0 event_window start with c1 > 0 end with c1 < 0 true_for('3001a');", show=True)
|
||||
tdSql.checkRows(3)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:23.000')
|
||||
tdSql.checkData(1, 2, 6)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:28.000')
|
||||
tdSql.checkData(2, 2, 5)
|
||||
|
||||
tdSql.query("select * from d_state_1", show=True)
|
||||
tdSql.checkRows(4)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:10.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:13.000')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(1, 2, 4)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:22.000')
|
||||
tdSql.checkData(2, 2, 5)
|
||||
tdSql.checkData(3, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(3, 1, '2025-01-01 00:00:30.000')
|
||||
tdSql.checkData(3, 2, 7)
|
||||
|
||||
tdSql.query("select * from d_state_2", show=True)
|
||||
tdSql.checkRows(4)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:10.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:13.000')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(1, 2, 4)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:23.000')
|
||||
tdSql.checkData(2, 2, 6)
|
||||
tdSql.checkData(3, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(3, 1, '2025-01-01 00:00:28.000')
|
||||
tdSql.checkData(3, 2, 5)
|
||||
|
||||
tdSql.query("select _wstart, _wend, count(*) from ct_1 state_window(c1) true_for(3s);", show=True)
|
||||
tdSql.checkRows(4)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:10.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:13.000')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(1, 2, 4)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:23.000')
|
||||
tdSql.checkData(2, 2, 6)
|
||||
tdSql.checkData(3, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(3, 1, '2025-01-01 00:00:28.000')
|
||||
tdSql.checkData(3, 2, 5)
|
||||
|
||||
tdSql.query("select * from d_state_3", show=True)
|
||||
tdSql.checkRows(5)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:06.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:08.999')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:10.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:13.000')
|
||||
tdSql.checkData(1, 2, 4)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(2, 2, 4)
|
||||
tdSql.checkData(3, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(3, 1, '2025-01-01 00:00:22.000')
|
||||
tdSql.checkData(3, 2, 5)
|
||||
tdSql.checkData(4, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(4, 1, '2025-01-01 00:00:30.000')
|
||||
tdSql.checkData(4, 2, 7)
|
||||
|
||||
tdSql.query("select * from d_state_4", show=True)
|
||||
tdSql.checkRows(5)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:06.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:08.999')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:10.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:13.000')
|
||||
tdSql.checkData(1, 2, 4)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(2, 2, 4)
|
||||
tdSql.checkData(3, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(3, 1, '2025-01-01 00:00:23.000')
|
||||
tdSql.checkData(3, 2, 6)
|
||||
tdSql.checkData(4, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(4, 1, '2025-01-01 00:00:28.000')
|
||||
tdSql.checkData(4, 2, 5)
|
||||
|
||||
tdSql.query("select _wstart, _wend, count(*) from ct_1 state_window(c1) true_for(2999);", show=True)
|
||||
tdSql.checkRows(5)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:06.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:08.999')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:10.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:13.000')
|
||||
tdSql.checkData(1, 2, 4)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(2, 2, 4)
|
||||
tdSql.checkData(3, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(3, 1, '2025-01-01 00:00:23.000')
|
||||
tdSql.checkData(3, 2, 6)
|
||||
tdSql.checkData(4, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(4, 1, '2025-01-01 00:00:28.000')
|
||||
tdSql.checkData(4, 2, 5)
|
||||
|
||||
tdSql.query("select * from d_state_5", show=True)
|
||||
tdSql.checkRows(3)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:22.000')
|
||||
tdSql.checkData(1, 2, 5)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:30.000')
|
||||
tdSql.checkData(2, 2, 7)
|
||||
|
||||
tdSql.query("select * from d_state_6", show=True)
|
||||
tdSql.checkRows(3)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:23.000')
|
||||
tdSql.checkData(1, 2, 6)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:28.000')
|
||||
tdSql.checkData(2, 2, 5)
|
||||
|
||||
tdSql.query("select _wstart, _wend, count(*) from ct_1 state_window(c1) true_for('3001a');", show=True)
|
||||
tdSql.checkRows(3)
|
||||
tdSql.checkData(0, 0, '2025-01-01 00:00:14.000')
|
||||
tdSql.checkData(0, 1, '2025-01-01 00:00:17.001')
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, '2025-01-01 00:00:18.000')
|
||||
tdSql.checkData(1, 1, '2025-01-01 00:00:23.000')
|
||||
tdSql.checkData(1, 2, 6)
|
||||
tdSql.checkData(2, 0, '2025-01-01 00:00:24.000')
|
||||
tdSql.checkData(2, 1, '2025-01-01 00:00:28.000')
|
||||
tdSql.checkData(2, 2, 5)
|
||||
|
||||
def test_abnormal_query(self):
|
||||
tdLog.info("test abnormal window true_for limit")
|
||||
tdSql.error("select _wstart, _wend, count(*) from ct_0 event_window start with c1 > 0 end with c1 < 0 true_for(3n);")
|
||||
tdSql.error("select _wstart, _wend, count(*) from ct_0 event_window start with c1 > 0 end with c1 < 0 true_for(3y);")
|
||||
tdSql.error("select _wstart, _wend, count(*) from ct_0 event_window start with c1 > 0 end with c1 < 0 true_for(-1);")
|
||||
tdSql.error("select _wstart, _wend, count(*) from ct_0 event_window start with c1 > 0 end with c1 < 0 true_for(-1a);")
|
||||
tdSql.error("select _wstart, _wend, count(*) from ct_0 event_window start with c1 > 0 end with c1 < 0 true_for('-1a');")
|
||||
tdSql.error("create stream s_ab into dst as select _wstart, _wend, count(*) from ct_0 event_window start with c1 > 0 end with c1 < 0 true_for(3n);")
|
||||
tdSql.error("create stream s_ab into dst as select _wstart, _wend, count(*) from ct_0 event_window start with c1 > 0 end with c1 < 0 true_for(3y);")
|
||||
tdSql.error("create stream s_ab into dst as select _wstart, _wend, count(*) from ct_0 event_window start with c1 > 0 end with c1 < 0 true_for(-1);")
|
||||
tdSql.error("create stream s_ab into dst as select _wstart, _wend, count(*) from ct_0 event_window start with c1 > 0 end with c1 < 0 true_for(-1a);")
|
||||
tdSql.error("create stream s_ab into dst as select _wstart, _wend, count(*) from ct_0 event_window start with c1 > 0 end with c1 < 0 true_for('-1a');")
|
||||
|
||||
def test_window_true_for_limit(self):
|
||||
""" Test the functionality of the true_for window function.
|
||||
|
||||
This test covers:
|
||||
1. Both batch query and stream computing scenarios.
|
||||
2. Two types of windows: event_window and state_window.
|
||||
3. Parameter types for true_for: numeric and string.
|
||||
4. Boundary value tests.
|
||||
5. Error case tests.
|
||||
|
||||
Since: v3.3.6.0
|
||||
|
||||
Labels: true_for, state_window, event_window
|
||||
|
||||
Jira: TS-5470
|
||||
|
||||
History:
|
||||
- 2025-02-21 Kuang Jinqing Created
|
||||
"""
|
||||
self.create_objects()
|
||||
self.insert_data()
|
||||
self.update_data()
|
||||
self.check_result()
|
||||
self.test_abnormal_query()
|
||||
|
||||
# run
|
||||
def run(self):
|
||||
self.test_window_true_for_limit()
|
||||
|
||||
# stop
|
||||
def stop(self):
|
||||
tdSql.close()
|
||||
tdLog.success(f"{__file__} successfully executed")
|
||||
|
||||
tdCases.addLinux(__file__, TDTestCase())
|
||||
tdCases.addWindows(__file__, TDTestCase())
|
|
@ -182,7 +182,9 @@ SScript *simParseScript(char *fileName) {
|
|||
SCommand *pCmd = NULL;
|
||||
SScript *script = NULL;
|
||||
|
||||
if ((fileName[0] == '.') || (fileName[0] == '/')) {
|
||||
if (fileName[0] == 0) {
|
||||
return NULL;
|
||||
} else if ((fileName[0] == '.') || (fileName[0] == '/')) {
|
||||
tstrncpy(name, fileName, PATH_MAX);
|
||||
} else {
|
||||
snprintf(name, PATH_MAX, "%s" TD_DIRSEP "%s", simScriptDir, fileName);
|
||||
|
|
|
@ -14,6 +14,7 @@ ENDIF()
|
|||
|
||||
INCLUDE_DIRECTORIES(${TD_SOURCE_DIR}/src/util/inc)
|
||||
|
||||
IF(TD_LINUX)
|
||||
ADD_EXECUTABLE(simTests "simTests.cpp")
|
||||
TARGET_LINK_LIBRARIES(simTests os util tsim_static gtest_main)
|
||||
|
||||
|
@ -21,3 +22,4 @@ ADD_TEST(
|
|||
NAME simTests
|
||||
COMMAND simTests
|
||||
)
|
||||
ENDIF()
|
|
@ -32,30 +32,30 @@ void simHandleSignal(int32_t signo, void *sigInfo, void *context);
|
|||
|
||||
TEST(simTests, parameters) {
|
||||
int32_t ret = 0;
|
||||
int32_t argc = 2;
|
||||
int32_t argc = 3;
|
||||
char *argv[4] = {0};
|
||||
|
||||
simSystemCleanUp();
|
||||
// argv[1] = "-c";
|
||||
// ret = simEntry(argc, argv);
|
||||
// EXPECT_EQ(ret, 0);
|
||||
argc = 3;
|
||||
argv[1] = "-f";
|
||||
argv[2] = "";
|
||||
ret = simEntry(argc, argv);
|
||||
EXPECT_EQ(ret, -1);
|
||||
|
||||
// argv[1] = "-f";
|
||||
// ret = simEntry(argc, argv);
|
||||
// EXPECT_EQ(ret, 0);
|
||||
argc = 4;
|
||||
argv[3] = "-v";
|
||||
ret = simEntry(argc, argv);
|
||||
EXPECT_EQ(ret, -1);
|
||||
|
||||
// argv[1] = "-v";
|
||||
// ret = simEntry(argc, argv);
|
||||
// EXPECT_EQ(ret, 0);
|
||||
argc = 5;
|
||||
argv[3] = "-c";
|
||||
argv[4] = "/etc/taos";
|
||||
ret = simEntry(argc, argv);
|
||||
EXPECT_EQ(ret, -1);
|
||||
|
||||
// argv[1] = "-h";
|
||||
// ret = simEntry(argc, argv);
|
||||
// EXPECT_EQ(ret, 0);
|
||||
argc = 4;
|
||||
argv[3] = "-h";
|
||||
ret = simEntry(argc, argv);
|
||||
EXPECT_EQ(ret, 0);
|
||||
|
||||
// simHandleSignal(0, NULL, NULL);
|
||||
|
||||
// simDebugFlag = 0;
|
||||
// argc = 1;
|
||||
// ret = simEntry(argc, argv);
|
||||
// EXPECT_EQ(ret, -1);
|
||||
simHandleSignal(0, NULL, NULL);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue