Merge branch '3.0' into merge/mainto3.0
|
@ -510,7 +510,6 @@ For the OpenTSDB text protocol, the parsing of timestamps follows its official p
|
|||
- tmq: [Input] Points to a valid ws_tmq_t structure pointer, which represents a TMQ consumer object.
|
||||
- timeout: [Input] Polling timeout in milliseconds, a negative number indicates a default timeout of 1 second.
|
||||
- **Return Value**: Non-`NULL`: Success, returns a pointer to a WS_RES structure, which contains the received message. `NULL`: indicates no data, the error code can be obtained through ws_errno (NULL), please refer to the reference manual for specific error message. WS_RES results are consistent with taos_query results, and information in WS_RES can be obtained through various query interfaces, such as schema, etc.
|
||||
|
||||
- `int32_t ws_tmq_consumer_close(ws_tmq_t *tmq)`
|
||||
- **Interface Description**: Used to close the ws_tmq_t structure. Must be used in conjunction with ws_tmq_consumer_new.
|
||||
- tmq: [Input] Points to a valid ws_tmq_t structure pointer, which represents a TMQ consumer object.
|
||||
|
@ -1196,7 +1195,7 @@ In addition to using SQL or parameter binding APIs to insert data, you can also
|
|||
- tmq: [Input] Points to a valid tmq_t structure pointer, representing a TMQ consumer object.
|
||||
- timeout: [Input] Polling timeout in milliseconds, a negative number indicates a default timeout of 1 second.
|
||||
- **Return Value**: Non-`NULL`: Success, returns a pointer to a TAOS_RES structure containing the received messages. `NULL`: indicates no data, the error code can be obtained through taos_errno (NULL), please refer to the reference manual for specific error message. TAOS_RES results are consistent with taos_query results, and information in TAOS_RES can be obtained through various query interfaces, such as schema, etc.
|
||||
|
||||
|
||||
- `int32_t tmq_consumer_close(tmq_t *tmq)`
|
||||
- **Interface Description**: Used to close a tmq_t structure. Must be used in conjunction with tmq_consumer_new.
|
||||
- tmq: [Input] Points to a valid tmq_t structure pointer, which represents a TMQ consumer object.
|
||||
|
|
|
@ -534,5 +534,6 @@ This document details the server error codes that may be encountered when using
|
|||
| 0x80004000 | Invalid message | The subscribed data is illegal, generally does not occur | Check the client-side error logs for details |
|
||||
| 0x80004001 | Consumer mismatch | The vnode requested for subscription and the reassigned vnode are inconsistent, usually occurs when new consumers join the same consumer group | Internal error, not exposed to users |
|
||||
| 0x80004002 | Consumer closed | The consumer no longer exists | Check if it has already been closed |
|
||||
| 0x80004017 | Invalid status, please subscribe topic first | tmq status invalidate | Without calling subscribe, directly poll data |
|
||||
| 0x80004017 | Invalid status, please subscribe topic first | tmq status invalidate | Without calling subscribe, directly poll data |
|
||||
| 0x80004100 | Stream task not exist | The stream computing task does not exist | Check the server-side error logs |
|
||||
|
||||
|
|
|
@ -65,6 +65,8 @@ TDengine 可以通过 MQTT 连接器从 MQTT 代理订阅数据并将其写入 T
|
|||
|
||||
在 **订阅主题及 QoS 配置** 中填写要消费的 Topic 名称和 QoS。使用如下格式设置: `{topic_name}::{qos}`(如:`my_topic::0`)。MQTT 协议 5.0 支持共享订阅,可以通过多个客户端订阅同一个 Topic 实现负载均衡,使用如下格式: `$share/{group_name}/{topic_name}::{qos}`,其中,`$share` 是固定前缀,表示启用共享订阅,`group_name` 是分组名称,类似 kafka 的消费者组。
|
||||
|
||||
在 **主题解析** 中填写 MQTT 主题解析规则,格式与 MQTT Topic 相同,将 MQTT Topic 各层级内容解析为对应变量名,`_` 表示解析时忽略当前层级。例如:MQTT Topic `a/+/c` 对应解析规则如果设置为 `v1/v2/_`,代表将第一层级的 `a` 赋值给变量 `v1`,第二层级的值(这里通配符 `+` 代表任意值)复制给变量 `v2`,第三层级的值 `c` 忽略,不会赋值给任何变量。在下方的 `payload 解析` 中,Topic 解析得到的变量同样可以参与各种转换和计算。
|
||||
|
||||
在 **数据压缩** 中,配置消息体压缩算法,taosX 在接收到消息后,使用对应的压缩算法对消息体进行解压缩获取原始数据。可选项 none(不压缩), gzip, snappy, lz4 和 zstd,默认为 none。
|
||||
|
||||
在 **字符编码** 中,配置消息体编码格式,taosX 在接收到消息后,使用对应的编码格式对消息体进行解码获取原始数据。可选项 UTF_8, GBK, GB18030, BIG5,默认为 UTF_8
|
||||
|
@ -138,7 +140,11 @@ json 数据支持 JSONObject 或者 JSONArray,使用 json 解析器可以解
|
|||
|
||||
#### 6.4 表映射
|
||||
|
||||
在 **目标超级表** 的下拉列表中选择一个目标超级表,也可以先点击右侧的 **创建超级表** 按钮
|
||||
在 **目标超级表** 的下拉列表中选择一个目标超级表,也可以先点击右侧的 **创建超级表** 按钮创建新的超级表。
|
||||
|
||||
当超级表需要根据消息动态生成时,可以选择 **创建模板**。其中,超级表名称,列名,列类型等均可以使用模板变量,当接收到数据后,程序会自动计算模板变量并生成对应的超级表模板,当数据库中超级表不存在时,会使用此模板创建超级表;对于已创建的超级表,如果缺少通过模板变量计算得到的列,也会自动创建对应列。
|
||||
|
||||

|
||||
|
||||
在 **映射** 中,填写目标超级表中的子表名称,例如:`t_{id}`。根据需求填写映射规则,其中 mapping 支持设置缺省值。
|
||||
|
||||
|
@ -148,6 +154,16 @@ json 数据支持 JSONObject 或者 JSONArray,使用 json 解析器可以解
|
|||
|
||||

|
||||
|
||||
如果超级表列为模板变量,在子表映射时会进行 pivot 操作,其中模板变量的值展开为列名,列的值为对应的映射列
|
||||
|
||||
例如:
|
||||
|
||||

|
||||
|
||||
预览结果为:
|
||||
|
||||

|
||||
|
||||
### 7. 高级选项
|
||||
|
||||
在 **消息等待队列大小** 中填写接收 MQTT 消息的缓存队列大小,当队列满时,新到达的数据会直接丢弃。可设置为 0,即不缓存。
|
||||
|
|
|
@ -150,7 +150,11 @@ let v3 = data["voltage"].split(",");
|
|||
|
||||
使用 json 规则解析出的电压是字符串表达的带单位形式,最终入库希望能使用 int 类型记录电压值和电流值,便于统计分析,此时就需要对电压进一步拆分;另外日期期望拆分为日期和时间入库。
|
||||
|
||||
如下图所示可以对源字段`ts`使用 split 规则拆分成日期和时间,对字段`voltage`使用 regex 提取出电压值和电压单位。split 规则需要设置**分隔符**和**拆分数量**,拆分后的字段命名规则为`{原字段名}_{顺序号}`,Regex 规则同解析过程中的一样,使用**命名捕获组**命名提取字段。
|
||||
如下图所示
|
||||
|
||||
* 对字段`ts`使用 split 规则拆分成日期和时间。split 规则需要设置**分隔符**和**拆分数量**,拆分后的字段命名规则为`{原字段名}_{顺序号}`。
|
||||
* 对字段`voltage`使用正则表达式 `^(?<voltage>[0-9]+)(?<voltage_unit>[a-zA-Z]+)$` 提取出电压值和电压单位,Regex 规则同解析过程中的一样,使用**命名捕获组**命名提取字段。
|
||||
* 对字段 `location` 使用 convert 转换,填写一个 JSON map 对象,其中 key 为字段 `current` 的值,`value` 为转换后的值。如图,`location` 字段的值 `"beijing.chaoyang.datun"` 被转换为 `"beijing.chaoyang.datunludong"`。
|
||||
|
||||

|
||||
|
||||
|
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 170 KiB |
|
@ -1184,7 +1184,7 @@ TDengine 的异步 API 均采用非阻塞调用模式。应用程序可以用多
|
|||
- **接口说明**:用于轮询消费数据,每一个消费者,只能单线程调用该接口。
|
||||
- tmq:[入参] 指向一个有效的 tmq_t 结构体指针,该结构体代表一个 TMQ 消费者对象。
|
||||
- timeout:[入参] 轮询的超时时间,单位为毫秒,负数表示默认超时1秒。
|
||||
- **返回值**:非 `NULL`:成功,返回一个指向 TAOS_RES 结构体的指针,该结构体包含了接收到的消息。。`NULL`:失败,表示没有数据。TAOS_RES 结果和 taos_query 返回结果一致,可通过查询的各种接口获取 TAOS_RES 里的信息,比如 schema 等。
|
||||
- **返回值**:非 `NULL`:成功,返回一个指向 TAOS_RES 结构体的指针,该结构体包含了接收到的消息。。`NULL`:表示没有数据,可通过taos_errno(NULL) 获取错误码,具体错误码参见参考手册。TAOS_RES 结果和 taos_query 返回结果一致,可通过查询的各种接口获取 TAOS_RES 里的信息,比如 schema 等。
|
||||
|
||||
- `int32_t tmq_consumer_close(tmq_t *tmq)`
|
||||
- **接口说明**:用于关闭 tmq_t 结构体。需与 tmq_consumer_new 配合使用。
|
||||
|
|
|
@ -554,6 +554,6 @@ description: TDengine 服务端的错误码列表和详细说明
|
|||
| 0x80004000 | Invalid message | 订阅到的数据非法,一般不会出现 | 具体查看client端的错误日志提示 |
|
||||
| 0x80004001 | Consumer mismatch | 订阅请求的vnode和重新分配的vnode不一致,一般存在于有新消费者加入相同消费者组里时 | 内部错误,不暴露给用户 |
|
||||
| 0x80004002 | Consumer closed | 消费者已经不存在了 | 查看是否已经close掉了 |
|
||||
| 0x80004017 | Invalid status, please subscribe topic first | 数据订阅状态不对 | 没有调用 subscribe,直接poll数据 |
|
||||
| 0x80004017 | Invalid status, please subscribe topic first | 数据订阅状态不对 | 没有调用 subscribe,直接 poll 数据 |
|
||||
| 0x80004100 | Stream task not exist | 流计算任务不存在 | 具体查看server端的错误日志 |
|
||||
|
||||
|
|
|
@ -1434,7 +1434,7 @@ static int32_t askEp(tmq_t* pTmq, void* param, bool sync, bool updateEpSet) {
|
|||
tqDebugC("consumer:0x%" PRIx64 " ask ep from mnode,QID:0x%" PRIx64, pTmq->consumerId, sendInfo->requestId);
|
||||
code = asyncSendMsgToServer(pTmq->pTscObj->pAppInfo->pTransporter, &epSet, NULL, sendInfo);
|
||||
|
||||
END:
|
||||
END:
|
||||
if (code != 0) {
|
||||
tqErrorC("%s failed at %d, msg:%s", __func__, lino, tstrerror(code));
|
||||
}
|
||||
|
@ -2243,7 +2243,7 @@ static int32_t doTmqPollImpl(tmq_t* pTmq, SMqClientTopic* pTopic, SMqClientVg* p
|
|||
pVg->seekUpdated = false; // reset this flag.
|
||||
pTmq->pollCnt++;
|
||||
|
||||
END:
|
||||
END:
|
||||
if (code != 0){
|
||||
tqErrorC("%s failed at %d msg:%s", __func__, lino, tstrerror(code));
|
||||
}
|
||||
|
@ -2468,7 +2468,7 @@ static SMqRspObj* processMqRsp(tmq_t* tmq, SMqRspWrapper* pRspWrapper){
|
|||
pRspObj->resType = pRspWrapper->tmqRspType == TMQ_MSG_TYPE__POLL_META_RSP ? RES_TYPE__TMQ_META : RES_TYPE__TMQ_BATCH_META;
|
||||
}
|
||||
|
||||
END:
|
||||
END:
|
||||
terrno = code;
|
||||
taosWUnLockLatch(&tmq->lock);
|
||||
return pRspObj;
|
||||
|
@ -2506,7 +2506,7 @@ static void* tmqHandleAllRsp(tmq_t* tmq) {
|
|||
}
|
||||
}
|
||||
|
||||
END:
|
||||
END:
|
||||
terrno = code;
|
||||
return returnVal;
|
||||
}
|
||||
|
@ -2549,7 +2549,7 @@ TAOS_RES* tmq_consumer_poll(tmq_t* tmq, int64_t timeout) {
|
|||
}
|
||||
}
|
||||
|
||||
END:
|
||||
END:
|
||||
terrno = code;
|
||||
if (tmq != NULL) {
|
||||
tqErrorC("consumer:0x%" PRIx64 " poll error at line:%d, msg:%s", tmq->consumerId, lino, tstrerror(terrno));
|
||||
|
|
|
@ -255,14 +255,8 @@ static void dmProcessRpcMsg(SDnode *pDnode, SRpcMsg *pRpc, SEpSet *pEpSet) {
|
|||
pRpc->info.wrapper = pWrapper;
|
||||
|
||||
EQItype itype = RPC_QITEM; // rsp msg is not restricted by tsQueueMemoryUsed
|
||||
if (IsReq(pRpc)) {
|
||||
if (pRpc->msgType == TDMT_SYNC_HEARTBEAT || pRpc->msgType == TDMT_SYNC_HEARTBEAT_REPLY)
|
||||
itype = DEF_QITEM;
|
||||
else
|
||||
itype = RPC_QITEM;
|
||||
} else {
|
||||
itype = DEF_QITEM;
|
||||
}
|
||||
if (IsReq(pRpc) && pRpc->msgType != TDMT_SYNC_HEARTBEAT && pRpc->msgType != TDMT_SYNC_HEARTBEAT_REPLY)
|
||||
itype = RPC_QITEM;
|
||||
code = taosAllocateQitem(sizeof(SRpcMsg), itype, pRpc->contLen, (void **)&pMsg);
|
||||
if (code) goto _OVER;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ ENDIF()
|
|||
add_custom_command(
|
||||
OUTPUT ${TD_SOURCE_DIR}/source/libs/parser/src/sql.c ${TD_SOURCE_DIR}/include/common/ttokenauto.h
|
||||
COMMAND echo "Running lemon process in ${TD_SOURCE_DIR}/source/libs/parser/inc"
|
||||
COMMAND ${TD_CONTRIB_DIR}/lemon/lemon sql.y || true
|
||||
COMMAND ${TD_CONTRIB_DIR}/lemon/lemon sql.y
|
||||
COMMAND echo "copy sql.c from ${TD_SOURCE_DIR}/source/libs/parser/inc/sql.c to ${TD_SOURCE_DIR}/source/libs/parser/src/"
|
||||
COMMAND mv ${TD_SOURCE_DIR}/source/libs/parser/inc/sql.c ${TD_SOURCE_DIR}/source/libs/parser/src/sql.c
|
||||
COMMAND mv ${TD_SOURCE_DIR}/source/libs/parser/inc/sql.h ${TD_SOURCE_DIR}/include/common/ttokenauto.h
|
||||
|
|
|
@ -24,6 +24,14 @@
|
|||
#include "parAst.h"
|
||||
|
||||
#define YYSTACKDEPTH 0
|
||||
|
||||
#define JOINED_TABLE_MK(jt, st, A, B, E, F, G, H) \
|
||||
{ \
|
||||
A = createJoinTableNode(pCxt, jt, st, B, E, F); \
|
||||
A = addWindowOffsetClause(pCxt, A, G); \
|
||||
A = addJLimitClause(pCxt, A, H); \
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
%syntax_error {
|
||||
|
@ -46,6 +54,8 @@
|
|||
%left NK_STAR NK_SLASH NK_REM.
|
||||
%left NK_CONCAT.
|
||||
|
||||
%right INNER LEFT RIGHT FULL OUTER SEMI ANTI ASOF WINDOW JOIN ON WINDOW_OFFSET JLIMIT.
|
||||
|
||||
/************************************************ create/alter account *****************************************/
|
||||
cmd ::= CREATE ACCOUNT NK_ID PASS NK_STRING account_options. { pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_EXPRIE_STATEMENT); }
|
||||
cmd ::= ALTER ACCOUNT NK_ID alter_account_options. { pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_EXPRIE_STATEMENT); }
|
||||
|
@ -1442,36 +1452,77 @@ parenthesized_joined_table(A) ::= NK_LP joined_table(B) NK_RP.
|
|||
parenthesized_joined_table(A) ::= NK_LP parenthesized_joined_table(B) NK_RP. { A = B; }
|
||||
|
||||
/************************************************ joined_table ********************************************************/
|
||||
joined_table(A) ::=
|
||||
table_reference(B) join_type(C) join_subtype(D) JOIN table_reference(E) join_on_clause_opt(F)
|
||||
window_offset_clause_opt(G) jlimit_clause_opt(H). {
|
||||
A = createJoinTableNode(pCxt, C, D, B, E, F);
|
||||
A = addWindowOffsetClause(pCxt, A, G);
|
||||
A = addJLimitClause(pCxt, A, H);
|
||||
}
|
||||
joined_table(A) ::= inner_joined(B). { A = B; }
|
||||
joined_table(A) ::= outer_joined(B). { A = B; }
|
||||
joined_table(A) ::= semi_joined(B). { A = B; }
|
||||
joined_table(A) ::= anti_joined(B). { A = B; }
|
||||
joined_table(A) ::= asof_joined(B). { A = B; }
|
||||
joined_table(A) ::= win_joined(B). { A = B; }
|
||||
|
||||
%type join_type { EJoinType }
|
||||
%destructor join_type { }
|
||||
join_type(A) ::= . { A = JOIN_TYPE_INNER; }
|
||||
join_type(A) ::= INNER. { A = JOIN_TYPE_INNER; }
|
||||
join_type(A) ::= LEFT. { A = JOIN_TYPE_LEFT; }
|
||||
join_type(A) ::= RIGHT. { A = JOIN_TYPE_RIGHT; }
|
||||
join_type(A) ::= FULL. { A = JOIN_TYPE_FULL; }
|
||||
/************************************************ inner join **********************************************************/
|
||||
inner_joined(A) ::=
|
||||
table_reference(B) JOIN table_reference(E) join_on_clause_opt(F). { JOINED_TABLE_MK(JOIN_TYPE_INNER, JOIN_STYPE_NONE, A, B, E, F, NULL, NULL); }
|
||||
|
||||
%type join_subtype { EJoinSubType }
|
||||
%destructor join_subtype { }
|
||||
join_subtype(A) ::= . { A = JOIN_STYPE_NONE; }
|
||||
join_subtype(A) ::= OUTER. { A = JOIN_STYPE_OUTER; }
|
||||
join_subtype(A) ::= SEMI. { A = JOIN_STYPE_SEMI; }
|
||||
join_subtype(A) ::= ANTI. { A = JOIN_STYPE_ANTI; }
|
||||
join_subtype(A) ::= ASOF. { A = JOIN_STYPE_ASOF; }
|
||||
join_subtype(A) ::= WINDOW. { A = JOIN_STYPE_WIN; }
|
||||
inner_joined(A) ::=
|
||||
table_reference(B) INNER JOIN table_reference(E) join_on_clause_opt(F). { JOINED_TABLE_MK(JOIN_TYPE_INNER, JOIN_STYPE_NONE, A, B, E, F, NULL, NULL); }
|
||||
|
||||
join_on_clause_opt(A) ::= . { A = NULL; }
|
||||
join_on_clause_opt(A) ::= ON search_condition(B). { A = B; }
|
||||
/************************************************ outer join **********************************************************/
|
||||
outer_joined(A) ::=
|
||||
table_reference(B) LEFT JOIN table_reference(E) join_on_clause(F). { JOINED_TABLE_MK(JOIN_TYPE_LEFT, JOIN_STYPE_OUTER, A, B, E, F, NULL, NULL); }
|
||||
|
||||
window_offset_clause_opt(A) ::= . { A = NULL; }
|
||||
window_offset_clause_opt(A) ::= WINDOW_OFFSET NK_LP window_offset_literal(B)
|
||||
outer_joined(A) ::=
|
||||
table_reference(B) RIGHT JOIN table_reference(E) join_on_clause(F). { JOINED_TABLE_MK(JOIN_TYPE_RIGHT, JOIN_STYPE_OUTER, A, B, E, F, NULL, NULL); }
|
||||
|
||||
outer_joined(A) ::=
|
||||
table_reference(B) FULL JOIN table_reference(E) join_on_clause(F). { JOINED_TABLE_MK(JOIN_TYPE_FULL, JOIN_STYPE_OUTER, A, B, E, F, NULL, NULL); }
|
||||
|
||||
outer_joined(A) ::=
|
||||
table_reference(B) LEFT OUTER JOIN table_reference(E) join_on_clause(F). { JOINED_TABLE_MK(JOIN_TYPE_LEFT, JOIN_STYPE_OUTER, A, B, E, F, NULL, NULL); }
|
||||
|
||||
outer_joined(A) ::=
|
||||
table_reference(B) RIGHT OUTER JOIN table_reference(E) join_on_clause(F). { JOINED_TABLE_MK(JOIN_TYPE_RIGHT, JOIN_STYPE_OUTER, A, B, E, F, NULL, NULL); }
|
||||
|
||||
outer_joined(A) ::=
|
||||
table_reference(B) FULL OUTER JOIN table_reference(E) join_on_clause(F). { JOINED_TABLE_MK(JOIN_TYPE_FULL, JOIN_STYPE_OUTER, A, B, E, F, NULL, NULL); }
|
||||
|
||||
/************************************************ semi join ***********************************************************/
|
||||
semi_joined(A) ::=
|
||||
table_reference(B) LEFT SEMI JOIN table_reference(E) join_on_clause(F). { JOINED_TABLE_MK(JOIN_TYPE_LEFT, JOIN_STYPE_SEMI, A, B, E, F, NULL, NULL); }
|
||||
|
||||
semi_joined(A) ::=
|
||||
table_reference(B) RIGHT SEMI JOIN table_reference(E) join_on_clause(F). { JOINED_TABLE_MK(JOIN_TYPE_RIGHT, JOIN_STYPE_SEMI, A, B, E, F, NULL, NULL); }
|
||||
|
||||
/************************************************ ansi join ***********************************************************/
|
||||
anti_joined(A) ::=
|
||||
table_reference(B) LEFT ANTI JOIN table_reference(E) join_on_clause(F). { JOINED_TABLE_MK(JOIN_TYPE_LEFT, JOIN_STYPE_ANTI, A, B, E, F, NULL, NULL); }
|
||||
|
||||
anti_joined(A) ::=
|
||||
table_reference(B) RIGHT ANTI JOIN table_reference(E) join_on_clause(F). { JOINED_TABLE_MK(JOIN_TYPE_RIGHT, JOIN_STYPE_ANTI, A, B, E, F, NULL, NULL); }
|
||||
|
||||
/************************************************ asof join ***********************************************************/
|
||||
asof_joined(A) ::=
|
||||
table_reference(B) LEFT ASOF JOIN table_reference(E) join_on_clause_opt(F)
|
||||
jlimit_clause_opt(H). { JOINED_TABLE_MK(JOIN_TYPE_LEFT, JOIN_STYPE_ASOF, A, B, E, F, NULL, H); }
|
||||
|
||||
asof_joined(A) ::=
|
||||
table_reference(B) RIGHT ASOF JOIN table_reference(E) join_on_clause_opt(F)
|
||||
jlimit_clause_opt(H). { JOINED_TABLE_MK(JOIN_TYPE_RIGHT, JOIN_STYPE_ASOF, A, B, E, F, NULL, H); }
|
||||
|
||||
/************************************************ window join *********************************************************/
|
||||
win_joined(A) ::=
|
||||
table_reference(B) LEFT WINDOW JOIN table_reference(E) join_on_clause_opt(F)
|
||||
window_offset_clause(G) jlimit_clause_opt(H). { JOINED_TABLE_MK(JOIN_TYPE_LEFT, JOIN_STYPE_WIN, A, B, E, F, G, H); }
|
||||
|
||||
win_joined(A) ::=
|
||||
table_reference(B) RIGHT WINDOW JOIN table_reference(E) join_on_clause_opt(F)
|
||||
window_offset_clause(G) jlimit_clause_opt(H). { JOINED_TABLE_MK(JOIN_TYPE_RIGHT, JOIN_STYPE_WIN, A, B, E, F, G, H); }
|
||||
|
||||
join_on_clause_opt(A) ::= . [ON] { A = NULL; }
|
||||
join_on_clause_opt(A) ::= join_on_clause(B). { A = B; }
|
||||
|
||||
join_on_clause(A) ::= ON search_condition(B). { A = B; }
|
||||
|
||||
window_offset_clause(A) ::= WINDOW_OFFSET NK_LP window_offset_literal(B)
|
||||
NK_COMMA window_offset_literal(C) NK_RP. { A = createWindowOffsetNode(pCxt, releaseRawExprNode(pCxt, B), releaseRawExprNode(pCxt, C)); }
|
||||
|
||||
window_offset_literal(A) ::= NK_VARIABLE(B). { A = createRawExprNode(pCxt, &B, createTimeOffsetValueNode(pCxt, &B)); }
|
||||
|
@ -1481,7 +1532,7 @@ window_offset_literal(A) ::= NK_MINUS(B) NK_VARIABLE(C).
|
|||
A = createRawExprNode(pCxt, &t, createTimeOffsetValueNode(pCxt, &t));
|
||||
}
|
||||
|
||||
jlimit_clause_opt(A) ::= . { A = NULL; }
|
||||
jlimit_clause_opt(A) ::= . [JLIMIT] { A = NULL; }
|
||||
jlimit_clause_opt(A) ::= JLIMIT NK_INTEGER(B). { A = createLimitNode(pCxt, &B, NULL); }
|
||||
|
||||
/************************************************ query_specification *************************************************/
|
||||
|
|
|
@ -7,9 +7,11 @@ TAOS_DEF_ERROR_CODE = ctypes.c_int32(0x80000000).value
|
|||
TSDB_CODE_MND_FUNC_NOT_EXIST = (TAOS_DEF_ERROR_CODE | 0x0374)
|
||||
|
||||
|
||||
TSDB_CODE_TSC_INVALID_OPERATION = (TAOS_DEF_ERROR_CODE | 0x0200)
|
||||
|
||||
TSDB_CODE_UDF_FUNC_EXEC_FAILURE = (TAOS_DEF_ERROR_CODE | 0x290A)
|
||||
|
||||
|
||||
TSDB_CODE_TSC_INTERNAL_ERROR = (TAOS_DEF_ERROR_CODE | 0x02FF)
|
||||
|
||||
TSDB_CODE_TSC_INVALID_OPERATION = (TAOS_DEF_ERROR_CODE | 0x0200)
|
||||
TSDB_CODE_PAR_SYNTAX_ERROR = (TAOS_DEF_ERROR_CODE | 0x2600)
|
||||
|
|
|
@ -356,11 +356,11 @@ class TDTestCase:
|
|||
def join_semantic_test(self, dbname=DBNAME):
|
||||
tdSql.query("select ct1.c_int from db.ct1 as ct1 join db1.ct1 as cy1 on ct1.ts=cy1.ts")
|
||||
tdSql.checkRows(self.rows)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 semi join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_TSC_INVALID_OPERATION)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 anti join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_TSC_INVALID_OPERATION)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 outer join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_TSC_INVALID_OPERATION)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 asof join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_TSC_INVALID_OPERATION)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 window join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_TSC_INVALID_OPERATION)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 semi join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_PAR_SYNTAX_ERROR)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 anti join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_PAR_SYNTAX_ERROR)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 outer join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_PAR_SYNTAX_ERROR)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 asof join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_PAR_SYNTAX_ERROR)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 window join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_PAR_SYNTAX_ERROR)
|
||||
|
||||
tdSql.query("select ct1.c_int from db.ct1 as ct1 join db1.ct1 as cy1 on ct1.ts=cy1.ts")
|
||||
tdSql.checkRows(self.rows)
|
||||
|
@ -374,7 +374,7 @@ class TDTestCase:
|
|||
tdSql.checkRows(self.rows)
|
||||
tdSql.query("select ct1.c_int from db.ct1 as ct1 left asof join db1.ct1 as cy1 on ct1.ts=cy1.ts")
|
||||
tdSql.checkRows(self.rows)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 left window join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_TSC_INVALID_OPERATION)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 left window join db1.ct1 as cy1 on ct1.ts=cy1.ts")
|
||||
|
||||
tdSql.query("select ct1.c_int from db.ct1 as ct1 right join db1.ct1 as cy1 on ct1.ts=cy1.ts")
|
||||
tdSql.checkRows(self.rows)
|
||||
|
@ -386,20 +386,18 @@ class TDTestCase:
|
|||
tdSql.checkRows(self.rows)
|
||||
tdSql.query("select ct1.c_int from db.ct1 as ct1 right asof join db1.ct1 as cy1 on ct1.ts=cy1.ts")
|
||||
tdSql.checkRows(self.rows)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 right window join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_TSC_INVALID_OPERATION)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 right window join db1.ct1 as cy1 on ct1.ts=cy1.ts")
|
||||
|
||||
tdSql.query("select ct1.c_int from db.ct1 as ct1 full join db1.ct1 as cy1 on ct1.ts=cy1.ts")
|
||||
tdSql.checkRows(self.rows)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 full semi join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_TSC_INVALID_OPERATION)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 full anti join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_TSC_INVALID_OPERATION)
|
||||
tdSql.query("select ct1.c_int from db.ct1 as ct1 full outer join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_TSC_INVALID_OPERATION)
|
||||
tdSql.checkRows(self.rows)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 full asof join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_TSC_INVALID_OPERATION)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 full window join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_TSC_INVALID_OPERATION)
|
||||
|
||||
|
||||
tdSql.query("select ct1.c_int from db.ct1 as ct1 full join db1.ct1 as cy1 on ct1.ts=cy1.ts join db1.ct1 as cy2 on ct1.ts=cy2.ts")
|
||||
tdSql.checkRows(self.rows)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 full semi join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_PAR_SYNTAX_ERROR)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 full anti join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_PAR_SYNTAX_ERROR)
|
||||
tdSql.query("select ct1.c_int from db.ct1 as ct1 full outer join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_PAR_SYNTAX_ERROR)
|
||||
tdSql.query("select * from db.ct1 join db.ct2 join db.ct3 on ct2.ts=ct3.ts on ct1.ts=ct2.ts")
|
||||
tdSql.checkRows(0)
|
||||
tdSql.execute(f'create table db.ct1_2 using db.stb1 tags ( 102 )')
|
||||
|
@ -408,6 +406,13 @@ class TDTestCase:
|
|||
tdSql.execute(f'insert into db.ct1_3 (select * from db.ct1)')
|
||||
tdSql.query("select * from db.ct1 join db.ct1_2 join db.ct1_3 on ct1_2.ts=ct1_3.ts on ct1.ts=ct1_2.ts")
|
||||
tdSql.checkRows(self.rows)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 full asof join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_PAR_SYNTAX_ERROR)
|
||||
tdSql.error("select ct1.c_int from db.ct1 as ct1 full window join db1.ct1 as cy1 on ct1.ts=cy1.ts", TSDB_CODE_PAR_SYNTAX_ERROR)
|
||||
|
||||
tdSql.query("select ct1.c_int from db.ct1 as ct1 left join db1.ct1 as cy1 on ct1.ts=cy1.ts")
|
||||
tdSql.checkRows(self.rows)
|
||||
tdSql.query("select ct1.c_int from db.ct1 as ct1 right join db1.ct1 as cy1 on ct1.ts=cy1.ts")
|
||||
tdSql.checkRows(self.rows)
|
||||
|
||||
tdSql.execute("drop table db.ct1_2")
|
||||
tdSql.execute("drop table db.ct1_3")
|
||||
|
|
|
@ -969,6 +969,11 @@ class TDTestCase:
|
|||
tdSql.checkData(0, 0, 6)
|
||||
tdSql.checkData(0, 1, 1734574929004)
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.query(f'select count(1), last_row(ts), last_row(c0) from (select * from (select * from {dbname}.meters))')
|
||||
tdSql.checkRows(1)
|
||||
tdSql.checkData(0, 0, 6)
|
||||
tdSql.checkData(0, 1, 1734574929004)
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.query(f'select tbname, last_row(ts), last_row(c0) from (select *, tbname from {dbname}.meters) group by tbname order by tbname')
|
||||
tdSql.checkRows(2)
|
||||
tdSql.checkData(0, 0, 'd0')
|
||||
|
@ -977,6 +982,14 @@ class TDTestCase:
|
|||
tdSql.checkData(1, 0, 'd1')
|
||||
tdSql.checkData(1, 1, 1734574929000)
|
||||
tdSql.checkData(1, 2, 1)
|
||||
tdSql.query(f'select tbname, last_row(ts), last_row(c0) from (select * from (select *, tbname from {dbname}.meters)) group by tbname order by tbname')
|
||||
tdSql.checkRows(2)
|
||||
tdSql.checkData(0, 0, 'd0')
|
||||
tdSql.checkData(0, 1, 1734574929004)
|
||||
tdSql.checkData(0, 2, 4)
|
||||
tdSql.checkData(1, 0, 'd1')
|
||||
tdSql.checkData(1, 1, 1734574929000)
|
||||
tdSql.checkData(1, 2, 1)
|
||||
tdSql.query(f'select count(1), last_row(ts), last_row(c0) from (select * from {dbname}.d0)')
|
||||
tdSql.checkRows(1)
|
||||
tdSql.checkData(0, 0, 5)
|
||||
|
@ -988,6 +1001,43 @@ class TDTestCase:
|
|||
tdSql.checkData(0, 1, 1734574929004)
|
||||
tdSql.checkData(0, 2, 4)
|
||||
|
||||
tdSql.execute(f'insert into {dbname}.d0 values(1734574930000, 1, 1, "c2", true)')
|
||||
tdSql.execute(f'insert into {dbname}.d0 values(1734574931000, 1, 1, "c2", true)')
|
||||
tdSql.execute(f'insert into {dbname}.d0 values(1734574932000, 1, 1, "c2", true)')
|
||||
tdSql.query(f'select last_row(_wstart) from (select _wstart, _wend, count(1) from {dbname}.meters interval(1s))')
|
||||
tdSql.checkRows(1)
|
||||
tdSql.checkData(0, 0, 1734574932000)
|
||||
tdSql.query(f'select last_row(_wstart), count(1) from (select _wstart, _wend, count(1) from {dbname}.meters interval(1s))')
|
||||
tdSql.checkRows(1)
|
||||
tdSql.checkData(0, 0, 1734574932000)
|
||||
tdSql.checkData(0, 1, 4)
|
||||
tdSql.query(f'select last_row(_wstart) from (select _wstart, _wend, count(1) from {dbname}.meters partition by tbname interval(1s))')
|
||||
tdSql.checkRows(1)
|
||||
tdSql.checkData(0, 0, 1734574932000)
|
||||
tdSql.query(f'select last_row(_wstart), count(1) from (select _wstart, _wend, count(1) from {dbname}.meters partition by tbname interval(1s))')
|
||||
tdSql.checkRows(1)
|
||||
tdSql.checkData(0, 0, 1734574932000)
|
||||
tdSql.checkData(0, 1, 5)
|
||||
tdSql.query(f'select first(_wstart), count(1) from (select _wstart, _wend, count(1) from {dbname}.meters interval(1s))')
|
||||
tdSql.checkRows(1)
|
||||
tdSql.checkData(0, 0, 1734574929000)
|
||||
tdSql.checkData(0, 1, 4)
|
||||
|
||||
tdSql.query(f'select last_row(_wstart) from (select * from (select _wstart, _wend, count(1) from {dbname}.meters interval(1s)))')
|
||||
tdSql.checkRows(1)
|
||||
tdSql.checkData(0, 0, 1734574932000)
|
||||
tdSql.query(f'select last_row(_wstart), count(1) from (select * from (select _wstart, _wend, count(1) from {dbname}.meters interval(1s)))')
|
||||
tdSql.checkRows(1)
|
||||
tdSql.checkData(0, 0, 1734574932000)
|
||||
tdSql.checkData(0, 1, 4)
|
||||
tdSql.query(f'select last_row(_wstart) from (select * from (select _wstart, _wend, count(1) from {dbname}.meters partition by tbname interval(1s)))')
|
||||
tdSql.checkRows(1)
|
||||
tdSql.checkData(0, 0, 1734574932000)
|
||||
tdSql.query(f'select last_row(_wstart), count(1) from (select * from (select _wstart, _wend, count(1) from {dbname}.meters partition by tbname interval(1s)))')
|
||||
tdSql.checkRows(1)
|
||||
tdSql.checkData(0, 0, 1734574932000)
|
||||
tdSql.checkData(0, 1, 5)
|
||||
|
||||
def run(self): # sourcery skip: extract-duplicate-method, remove-redundant-fstring
|
||||
# tdSql.prepare()
|
||||
|
||||
|
@ -1023,7 +1073,6 @@ class TDTestCase:
|
|||
|
||||
self.lastrow_in_subquery("db1")
|
||||
|
||||
|
||||
def stop(self):
|
||||
tdSql.close()
|
||||
tdLog.success(f"{__file__} successfully executed")
|
||||
|
|