enh: cols in having clause

This commit is contained in:
facetosea 2025-02-19 13:15:25 +08:00
parent 01518aae39
commit 4a3343a667
3 changed files with 76 additions and 7 deletions

View File

@ -272,7 +272,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 4
#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

View File

@ -4111,7 +4111,7 @@ static int32_t checkWinJoinAggColCoexist(STranslateContext* pCxt, SSelectStmt* p
}
static int32_t checkHavingGroupBy(STranslateContext* pCxt, SSelectStmt* pSelect) {
int32_t code = TSDB_CODE_SUCCESS;
int32_t code = TSDB_CODE_SUCCESS;
if (NULL == getGroupByList(pCxt) && NULL == pSelect->pPartitionByList && NULL == pSelect->pWindow &&
!isWindowJoinStmt(pSelect)) {
return code;
@ -5473,22 +5473,26 @@ static int32_t translateClausePosition(STranslateContext* pCxt, SNodeList* pProj
}
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) {
if (TSDB_CODE_SUCCESS == code && LIST_LENGTH(pSelect->pProjectionBindList) > len) {
code = translateExprList(pCxt, pSelect->pProjectionBindList);
}
if (pSelect->pProjectionBindList != NULL) {
pSelect->hasAggFuncs = true;
pSelect->hasAggFuncs = true;
}
return code;
}
@ -5745,10 +5749,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;
@ -5758,9 +5770,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) {
@ -7554,6 +7564,22 @@ _end:
return code;
}
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;

View File

@ -1113,6 +1113,47 @@ class TDTestCase:
tdSql.checkData(2, 2, "2022-09-29 15:15:03")
tdSql.checkData(3, 1, "2022-09-30 15:15:04")
tdSql.checkData(3, 2, "2022-09-30 15:15:03")
def having_test(self, table_name, is_subquery):
tdLog.info("having_test")
t1 = f"from {table_name} "
tdSql.query(f'select tbname, cols(last(ts), ts) {t1} group by tbname having cols(last(ts), ts) > 1734574929000')
tdSql.checkRows(1)
tdSql.checkCols(2)
tdSql.checkData(0, 0, 'd0')
tdSql.checkData(0, 1, 1734574929014)
tdSql.query(f'select tbname, cols(last(ts), ts) {t1} group by tbname having cols(last(ts), ts) = 1734574929000')
tdSql.checkRows(1)
tdSql.checkCols(2)
tdSql.checkData(0, 0, 'd1')
tdSql.checkData(0, 1, 1734574929000)
tdSql.query(f'select tbname, cols(last(ts), ts) {t1} group by tbname having cols(last(ts), ts) < 1734574929000')
tdSql.checkRows(0)
tdSql.query(f'select tbname, cols(last(ts), ts) {t1} group by tbname having cols(last(ts), ts) != 1734574929000')
tdSql.checkRows(1)
tdSql.checkCols(2)
tdSql.checkData(0, 0, 'd0')
tdSql.checkData(0, 1, 1734574929014)
tdSql.query(f'select tbname, cols(last(ts), ts) {t1} group by tbname having cols(last(ts), ts) >= 1734574929000')
tdSql.checkRows(2)
tdSql.checkCols(2)
tdSql.checkData(0, 0, 'd1')
tdSql.checkData(0, 1, 1734574929000)
tdSql.checkData(1, 0, 'd0')
tdSql.checkData(1, 1, 1734574929014)
tdSql.query(f'select tbname, cols(last(ts), ts) {t1} group by tbname having cols(last(ts), ts) <= 1734574929000')
tdSql.checkRows(1)
tdSql.checkCols(2)
tdSql.checkData(0, 0, 'd1')
tdSql.checkData(0, 1, 1734574929000)
tdSql.query(f'select tbname, cols(last(ts), ts) {t1} group by tbname having cols(last(c0), ts) between 1734574929000 and 1734574929014')
tdSql.checkRows(2)
tdSql.checkCols(2)
tdSql.checkData(0, 0, 'd1')
tdSql.checkData(0, 1, 1734574929000)
tdSql.checkData(1, 0, 'd0')
tdSql.checkData(1, 1, 1734574929014)
def run(self):
self.funcNestTest()
@ -1128,6 +1169,8 @@ class TDTestCase:
self.include_null_test()
self.long_column_name_test()
self.test1()
self.having_test("test.meters", False)
self.having_test("(select tbname, * from test.meters)", True)
def stop(self):