Skip to content

feat: support zeroth state in state window#33294

Merged
guanshengliang merged 7 commits into3.0from
feat/3.0/TD-37942
Oct 22, 2025
Merged

feat: support zeroth state in state window#33294
guanshengliang merged 7 commits into3.0from
feat/3.0/TD-37942

Conversation

@Tony2h
Copy link
Copy Markdown
Member

@Tony2h Tony2h commented Oct 17, 2025

Description

Please briefly describe the code changes in this pull request.

Checklist

Please check the items in the checklist if applicable.

  • Is the user manual updated?
  • Are the test cases passed and automated?
  • Is there no significant decrease in test coverage?

@Tony2h
Copy link
Copy Markdown
Member Author

Tony2h commented Oct 17, 2025

/gemini review

@gemini-code-assist

This comment was marked as off-topic.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for a 'zeroth state' in state window functions, which allows for filtering out a baseline or initial state from the window results. The changes are comprehensive, touching the parser, query AST, serialization/deserialization logic, and the stream processing engine. A new test suite has been added to validate this functionality. My review identified a couple of issues: a potential correctness bug in the state comparison logic due to incomplete type handling, and a minor memory leak in an error path within the parser's translation phase. Overall, this is a solid feature addition.

Comment on lines +7586 to +7590
if (IS_INTEGER_TYPE(type)) {
return memcmp(pStateData, &pZerothState->datum.i, bytes) == 0;
}
// is boolean type
return memcmp(pStateData, &pZerothState->datum.b, bytes) == 0;

This comment was marked as resolved.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

fixed

Comment on lines +7596 to +7598
if (TSDB_CODE_SUCCESS == code) {
code = scalarCalculateConstants(pCastFunc, &pStateWin->pZeroth);
}

This comment was marked as spam.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

pCastFunc is the new node, no memleak here

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for a "zeroth state" in state windows, which is a valuable addition for filtering out initial or uninteresting states. The changes are comprehensive, touching data structures, serialization, parsing, query translation, and execution logic. The inclusion of a new test suite is commendable.

I have identified a few issues that should be addressed:

  • A correctness bug in the state comparison logic where floating-point types are not handled correctly.
  • A couple of memory leaks in the parser and translator due to improper handling of temporary objects.

Fixing these issues will ensure the feature is robust and reliable. Overall, this is a good contribution.

Comment on lines +7576 to +7591
bool stIsStateEqualZeroth(char* pStateData, void* pZeroth, int32_t bytes) {
if (pStateData == NULL || pZeroth == NULL) {
return false;
}

SValueNode* pZerothState = (SValueNode*)pZeroth;
int8_t type = pZerothState->node.resType.type;
if (IS_VAR_DATA_TYPE(type)) {
return memcmp(pStateData, pZerothState->datum.p, bytes) == 0;
}
if (IS_INTEGER_TYPE(type)) {
return memcmp(pStateData, &pZerothState->datum.i, bytes) == 0;
}
// is boolean type
return memcmp(pStateData, &pZerothState->datum.b, bytes) == 0;
}

This comment was marked as spam.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

no need to handle float type.

Comment on lines +1581 to +1589
if (pOptions != NULL) {
if (pOptions->length >= 1) {
state->pExtend = nodesListGetNode(pOptions, 0);
}
if (pOptions->length == 2) {
state->pZeroth = nodesListGetNode(pOptions, 1);
}
}
nodesClearList(pOptions);

This comment was marked as outdated.

Comment on lines +7594 to +7598
SNode* pCastFunc = NULL;
int32_t code = createCastFunc(pCxt, pStateWin->pZeroth, targetDt, &pCastFunc);
if (TSDB_CODE_SUCCESS == code) {
code = scalarCalculateConstants(pCastFunc, &pStateWin->pZeroth);
}

This comment was marked as duplicate.

@Tony2h Tony2h force-pushed the feat/3.0/TD-37942 branch from f50c3f8 to da5cd73 Compare October 17, 2025 09:36
@Tony2h
Copy link
Copy Markdown
Member Author

Tony2h commented Oct 17, 2025

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for a 'zeroth state' in state windows, which allows a specific state value to be ignored when forming windows. The changes span parsing, query translation, serialization, and stream processing, and include a comprehensive new test suite. The implementation is solid, but I've identified one issue where floating-point types are not handled in the stream processing logic for state comparison. My review includes a suggestion to address this.

Comment on lines +7583 to +7592
if (IS_VAR_DATA_TYPE(type)) {
return memcmp(pStateData, pZerothState->datum.p, bytes) == 0;
}
if (IS_INTEGER_TYPE(type)) {
return memcmp(pStateData, &pZerothState->datum.i, bytes) == 0;
}
if (IS_BOOLEAN_TYPE(type)) {
return memcmp(pStateData, &pZerothState->datum.b, bytes) == 0;
}
return false;

This comment was marked as duplicate.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

这里的类型是不是不完全?比如 timestamp ?如果不期望走到最后的 return false,可以加上报错。

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Tony Zhang seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@Tony2h Tony2h requested a review from zitsen as a code owner October 20, 2025 02:09
}
if (pTask->notifyEventType & STRIGGER_EVENT_WINDOW_CLOSE) {
if (stIsStateEqualZeroth(pStateData, pTask->pStateZeroth, bytes)) {
pWin = taosArrayPop(pContext->pWindows);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

这是实时计算的逻辑,历史计算那里也要加,对应函数: stHistoryGroupDoStateCheck
测试历史计算:写数据 => 使用 fill_history 选项建流 => 检查流计算结果

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

其实最通顺的方式应该是加在 stRealtimeGroupGenCalcParams,参考里面关于 ignoreNoDataTrigger 的逻辑

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

这是实时计算的逻辑,历史计算那里也要加,对应函数: stHistoryGroupDoStateCheck 测试历史计算:写数据 => 使用 fill_history 选项建流 => 检查流计算结果

fixed,支持历史数据触发,已添加测试用例

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

其实最通顺的方式应该是加在 stRealtimeGroupGenCalcParams,参考里面关于 ignoreNoDataTrigger 的逻辑

这个目前做不到,因为在这个函数里拿不到每个窗口的状态值,只能在关闭窗口时立即判断

- window_clause: 指定数据按照窗口进行切分并进行聚合,是时序数据库特色查询。详细信息可参阅特色查询章节 [TDengine TSDB 特色查询](../distinguished)。
- SESSION: 会话窗口,ts_col 指定时间戳主键列,tol_val 指定时间间隔,正值,时间精度可选 1n、1u、1a、1s、1m、1h、1d、1w,如 SESSION(ts, 12s)。
- STATE_WINDOW: 状态窗口,extend 指定窗口在开始结束时的扩展策略,可选值为 0(默认值)、1、2,分别代表无扩展、向后扩展、向前扩展;TRUE_FOR 指定窗口最小持续时长,时间范围为正值,精度可选 1n、1u、1a、1s、1m、1h、1d、1w,如 TRUE_FOR(1a)。
- STATE_WINDOW: 状态窗口,extend 指定窗口在开始结束时的扩展策略,可选值为 0(默认值)、1、2,分别代表无扩展、向后扩展、向前扩展;zeroth state 指定“零状态”,状态列为此状态的窗口将不会被计算和输出;TRUE_FOR 指定窗口最小持续时长,时间范围为正值,精度可选 1n、1u、1a、1s、1m、1h、1d、1w,如 TRUE_FOR(1a)。
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

zeroth_state可以写什么没有说的很清楚,比如常量、列、运算符、函数可以吗

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

fixed

SValueNode* pZerothState = (SValueNode*)pZeroth;
int8_t type = pZerothState->node.resType.type;
if (IS_VAR_DATA_TYPE(type)) {
return memcmp(pStateData, pZerothState->datum.p, bytes) == 0;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

这里有越界读风险,可以参考字符串比较的实现

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

fixed

@Tony2h
Copy link
Copy Markdown
Member Author

Tony2h commented Oct 21, 2025

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

The pull request introduces the zeroth_state parameter to the STATE_WINDOW function, allowing users to exclude windows with a specific state from calculations. The changes involve modifications to documentation files, header files, source code, and test cases to accommodate this new functionality. The code review focuses on correctness and potential issues arising from the added functionality.

TAOS_CHECK_EXIT(tEncodeI16(pEncoder, pMsg->trigger.stateWin.extend));
TAOS_CHECK_EXIT(tEncodeI64(pEncoder, pMsg->trigger.stateWin.trueForDuration));
int32_t stateWindowZerothLen =
pMsg->trigger.stateWin.zeroth == NULL ? 0 : (int32_t)strlen((char*)pMsg->trigger.stateWin.zeroth) + 1;

This comment was marked as spam.

Comment on lines +9725 to +9729
int32_t stIsStateEqualZeroth(void* pStateData, void* pZeroth, bool* pIsEqual) {
int32_t code = TSDB_CODE_SUCCESS;
if (pStateData == NULL || pZeroth == NULL) {
return false;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

If pStateData is NULL, the function should return true to indicate that the state data is equal to the zeroth state, since there is no state data to compare against. This is a critical bug that needs to be fixed.

int32_t stIsStateEqualZeroth(void* pStateData, void* pZeroth, bool* pIsEqual) {
  int32_t code = TSDB_CODE_SUCCESS;
  if (pStateData == NULL || pZeroth == NULL) {
    *pIsEqual = true; // Treat NULL state data as equal to zeroth state
    return code;
  }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

fixed

int32_t stIsStateEqualZeroth(void* pStateData, void* pZeroth, bool* pIsEqual) {
int32_t code = TSDB_CODE_SUCCESS;
if (pStateData == NULL || pZeroth == NULL) {
return false;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

This return statement will cause the function to return false without setting the pIsEqual parameter, which is unexpected. The return type is int32_t, but the function is returning a boolean value. This is a high severity issue that needs to be fixed.

  if (pStateData == NULL || pZeroth == NULL) {
    *pIsEqual = true; // Treat NULL state data as equal to zeroth state
    return code;
  }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

fixed

Comment on lines +7595 to +7601
int32_t code = createCastFunc(pCxt, pStateWin->pZeroth, targetDt, &pCastFunc);
if (TSDB_CODE_SUCCESS == code) {
code = scalarCalculateConstants(pCastFunc, &pStateWin->pZeroth);
}
if (TSDB_CODE_SUCCESS != code) {
code = generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_WRONG_VALUE_TYPE, "Zeroth value type mismatch");
}

This comment was marked as spam.

Comment on lines +9733 to +9734
if (IS_VAR_DATA_TYPE(type)) {
*pIsEqual = compareLenPrefixedStr(pStateData, pZerothState->datum.p) == 0;

This comment was marked as spam.

tdSql.error("select count(*) from ntb state_window(s, 1.5)")
tdSql.error("select count(*) from ntb state_window(s, *)")
tdSql.error("select count(*) from ntb state_window(s, '2025-09-03')")
tdSql.error("select count(*) from ntb state_window(s, 1, 2)")

This comment was marked as spam.

@guanshengliang guanshengliang merged commit 7255df3 into 3.0 Oct 22, 2025
28 of 31 checks passed
happyguoxy added a commit that referenced this pull request Oct 23, 2025
feat: support zeroth state in state window (#33294)
@minhuinie minhuinie deleted the feat/3.0/TD-37942 branch February 4, 2026 02:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants