Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/libs/nodes/querynodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,7 @@ typedef struct SSelectStmt {
bool isEmptyResult;
bool isSubquery;
bool hasAggFuncs;
bool hasNonSelectAggFuncs;
bool hasRepeatScanFuncs;
bool hasIndefiniteRowsFunc;
bool hasMultiRowsFunc;
Expand Down
1 change: 1 addition & 0 deletions source/libs/nodes/src/nodesCloneFuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1172,6 +1172,7 @@ static int32_t selectStmtCopy(const SSelectStmt* pSrc, SSelectStmt* pDst) {
COPY_SCALAR_FIELD(timeLineFromOrderBy);
COPY_SCALAR_FIELD(timeLineCurMode);
COPY_SCALAR_FIELD(hasAggFuncs);
COPY_SCALAR_FIELD(hasNonSelectAggFuncs);
COPY_SCALAR_FIELD(hasRepeatScanFuncs);
COPY_SCALAR_FIELD(hasIndefiniteRowsFunc);
COPY_SCALAR_FIELD(hasMultiRowsFunc);
Expand Down
7 changes: 7 additions & 0 deletions source/libs/nodes/src/nodesCodeFuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -7925,6 +7925,7 @@ static const char* jkSelectStmtLimit = "Limit";
static const char* jkSelectStmtSlimit = "Slimit";
static const char* jkSelectStmtStmtName = "StmtName";
static const char* jkSelectStmtHasAggFuncs = "HasAggFuncs";
static const char* jkSelectStmtHasNonSelectAggFuncs = "HasNonSelectAggFuncs";
static const char* jkSelectStmtInterpFuncs = "HasInterpFuncs";
static const char* jkSelectStmtInterpFill = "InterpFill";
static const char* jkSelectStmtInterpEvery = "InterpEvery";
Expand Down Expand Up @@ -7973,6 +7974,9 @@ static int32_t selectStmtToJson(const void* pObj, SJson* pJson) {
if (TSDB_CODE_SUCCESS == code) {
code = tjsonAddBoolToObject(pJson, jkSelectStmtHasAggFuncs, pNode->hasAggFuncs);
}
if (TSDB_CODE_SUCCESS == code) {
code = tjsonAddBoolToObject(pJson, jkSelectStmtHasNonSelectAggFuncs, pNode->hasNonSelectAggFuncs);
}
if (TSDB_CODE_SUCCESS == code) {
code = tjsonAddBoolToObject(pJson, jkSelectStmtInterpFuncs, pNode->hasInterpFunc);
}
Expand Down Expand Up @@ -8031,6 +8035,9 @@ static int32_t jsonToSelectStmt(const SJson* pJson, void* pObj) {
if (TSDB_CODE_SUCCESS == code) {
code = tjsonGetBoolValue(pJson, jkSelectStmtHasAggFuncs, &pNode->hasAggFuncs);
}
if (TSDB_CODE_SUCCESS == code) {
code = tjsonGetBoolValue(pJson, jkSelectStmtHasNonSelectAggFuncs, &pNode->hasNonSelectAggFuncs);
}
if (TSDB_CODE_SUCCESS == code) {
code = tjsonGetBoolValue(pJson, jkSelectStmtInterpFuncs, &pNode->hasInterpFunc);
}
Expand Down
66 changes: 60 additions & 6 deletions source/libs/parser/src/parTranslater.c
Original file line number Diff line number Diff line change
Expand Up @@ -3584,10 +3584,17 @@ static int32_t translateAggFunc(STranslateContext* pCxt, SFunctionNode* pFunc) {
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
}
// The auto-generated COUNT function in the DELETE statement is legal
if (isSelectStmt(pCxt->pCurrStmt) &&
(((SSelectStmt*)pCxt->pCurrStmt)->hasIndefiniteRowsFunc || ((SSelectStmt*)pCxt->pCurrStmt)->hasMultiRowsFunc)) {
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC,
"Aggregate func '%s' mixed with other multi-row functions", pFunc->functionName);
if (isSelectStmt(pCxt->pCurrStmt)) {
SSelectStmt* pSelect = (SSelectStmt*)pCxt->pCurrStmt;
bool mixedWithIndefOrMulti = pSelect->hasIndefiniteRowsFunc || pSelect->hasMultiRowsFunc;
// select-only agg funcs (first/last/min/max/mode/last_row, excluding top/bottom/sample)
// are allowed to coexist with indefinite-row funcs
bool isAllowedSelectAggWithIndef = pSelect->hasIndefiniteRowsFunc && !pSelect->hasMultiRowsFunc &&
fmIsSelectFunc(pFunc->funcId) && !fmIsMultiRowsFunc(pFunc->funcId);
if (mixedWithIndefOrMulti && !isAllowedSelectAggWithIndef) {
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC,
"Aggregate func '%s' mixed with other multi-row functions", pFunc->functionName);
}
}

if (isCountStar(pFunc)) {
Expand Down Expand Up @@ -3620,7 +3627,7 @@ static int32_t translateIndefiniteRowsFunc(STranslateContext* pCxt, SFunctionNod
"Indefinite rows function '%s' only allowed in select clause", pFunc->functionName);
}
SSelectStmt* pSelect = (SSelectStmt*)pCxt->pCurrStmt;
if (pSelect->hasAggFuncs || pSelect->hasMultiRowsFunc) {
if (pSelect->hasNonSelectAggFuncs || pSelect->hasMultiRowsFunc) {
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC,
"Indefinite rows function '%s' mixed with other multi-row functions",
pFunc->functionName);
Expand Down Expand Up @@ -4263,6 +4270,9 @@ static void setFuncClassification(STranslateContext* pCxt, SFunctionNode* pFunc)
if (NULL != pCurrStmt && QUERY_NODE_SELECT_STMT == nodeType(pCurrStmt)) {
SSelectStmt* pSelect = (SSelectStmt*)pCurrStmt;
pSelect->hasAggFuncs = pSelect->hasAggFuncs ? true : fmIsAggFunc(pFunc->funcId);
if (fmIsAggFunc(pFunc->funcId) && !fmIsSelectFunc(pFunc->funcId)) {
pSelect->hasNonSelectAggFuncs = true;
}
pSelect->hasCountFunc = pSelect->hasCountFunc ? true : (FUNCTION_TYPE_COUNT == pFunc->funcType);
pSelect->hasRepeatScanFuncs = pSelect->hasRepeatScanFuncs ? true : fmIsRepeatScanFunc(pFunc->funcId);

Expand Down Expand Up @@ -5487,7 +5497,17 @@ static int32_t checkGroupByListForBlob(STranslateContext* pCxt, SSelectStmt* pSe
}

static EDealRes rewriteColsToSelectValFuncImpl(SNode** pNode, void* pContext) {
if (isAggFunc(*pNode) || isIndefiniteRowsFunc(*pNode)) {
if (isAggFunc(*pNode)) {
return DEAL_RES_IGNORE_CHILD;
}
if (isIndefiniteRowsFunc(*pNode)) {
STranslateContext* pCxt = (STranslateContext*)pContext;
SSelectStmt* pSelect = (SSelectStmt*)pCxt->pCurrStmt;
// When indef-row funcs coexist with select agg funcs, descend into indef-row
// functions so their column params get wrapped with _select_value().
if (pSelect && pSelect->hasAggFuncs && !pSelect->hasNonSelectAggFuncs) {
return DEAL_RES_CONTINUE;
}
return DEAL_RES_IGNORE_CHILD;
}
if (isScanPseudoColumnFunc(*pNode) || QUERY_NODE_COLUMN == nodeType(*pNode)) {
Expand All @@ -5504,6 +5524,35 @@ static int32_t rewriteColsToSelectValFunc(STranslateContext* pCxt, SSelectStmt*
return pCxt->errCode;
}

// Rewrite walker: descend into indefinite-row functions to wrap their column params
// with _select_value() so the Agg node can output them.
static EDealRes rewriteIndefColsToSelectValImpl(SNode** pNode, void* pContext) {
if (isAggFunc(*pNode)) {
return DEAL_RES_IGNORE_CHILD;
}
if (isIndefiniteRowsFunc(*pNode)) {
return DEAL_RES_CONTINUE;
}
if (isScanPseudoColumnFunc(*pNode) || QUERY_NODE_COLUMN == nodeType(*pNode)) {
return rewriteColToSelectValFunc((STranslateContext*)pContext, pNode);
}
return DEAL_RES_CONTINUE;
}

// When indefinite-row functions coexist with select agg functions, the Agg node
// sits below IndefRows. Raw columns inside indef functions (e.g. c1 in diff(c1))
// must be wrapped with _select_value() so Agg outputs them for IndefRows to consume.
static int32_t rewriteIndefColsForSelectAgg(STranslateContext* pCxt, SSelectStmt* pSelect) {
if (!pSelect->hasIndefiniteRowsFunc || !pSelect->hasAggFuncs || pSelect->hasNonSelectAggFuncs) {
return TSDB_CODE_SUCCESS;
}
nodesRewriteExprs(pSelect->pProjectionList, rewriteIndefColsToSelectValImpl, pCxt);
if (TSDB_CODE_SUCCESS == pCxt->errCode) {
nodesRewriteExprs(pSelect->pOrderByList, rewriteIndefColsToSelectValImpl, pCxt);
}
return pCxt->errCode;
Comment thread
facetosea marked this conversation as resolved.
}

typedef struct CheckAggColCoexistCxt {
STranslateContext* pTranslateCxt;
bool existCol;
Expand Down Expand Up @@ -11676,6 +11725,11 @@ static int32_t translateSelectFrom(STranslateContext* pCxt, SSelectStmt* pSelect
if (TSDB_CODE_SUCCESS == code) {
code = appendTsForImplicitTsFunc(pCxt, pSelect);
}
// After implicit ts params are appended to indef-row functions, wrap them with
// _select_value() so the Agg node can output them for IndefRows to consume.
if (TSDB_CODE_SUCCESS == code) {
code = rewriteIndefColsForSelectAgg(pCxt, pSelect);
}
if (TSDB_CODE_SUCCESS == code) {
code = appendPkParamForPkFunc(pCxt, pSelect);
}
Expand Down
52 changes: 49 additions & 3 deletions source/libs/planner/src/planLogicCreater.c
Original file line number Diff line number Diff line change
Expand Up @@ -1680,8 +1680,11 @@ static int32_t createAggLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect,
}

static int32_t createIndefRowsFuncLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SLogicNode** pLogicNode) {
// top/bottom are both an aggregate function and a indefinite rows function
if (!pSelect->hasIndefiniteRowsFunc || pSelect->hasAggFuncs || NULL != pSelect->pWindow) {
// Allow indefinite rows functions to coexist with selection functions (agg + select).
// Block when non-select agg funcs or window present.
if (!pSelect->hasIndefiniteRowsFunc ||
(pSelect->hasAggFuncs && pSelect->hasNonSelectAggFuncs) ||
NULL != pSelect->pWindow) {
return TSDB_CODE_SUCCESS;
}

Expand All @@ -1698,8 +1701,31 @@ static int32_t createIndefRowsFuncLogicNode(SLogicPlanContext* pCxt, SSelectStmt
pIdfRowsFunc->node.requireDataOrder = getRequireDataOrder(pIdfRowsFunc->isTimeLineFunc, pSelect);
pIdfRowsFunc->node.resultDataOrder = pIdfRowsFunc->node.requireDataOrder;

// When coexisting with select agg funcs, collect pass-through columns from Agg output
// BEFORE rewriteExprsForSelect (which would turn indef funcs into column nodes too).
// After Agg rewrite, agg functions in pProjectionList are already column nodes referencing
// Agg output. We collect these now and add them to pFuncs/pTargets below.
SNodeList* pPassThroughCols = NULL;
if (pSelect->hasAggFuncs && !pSelect->hasNonSelectAggFuncs) {
SNode* pNode = NULL;
FOREACH(pNode, pSelect->pProjectionList) {
if (QUERY_NODE_COLUMN == nodeType(pNode)) {
SNode* pClone = NULL;
code = nodesCloneNode(pNode, &pClone);
if (TSDB_CODE_SUCCESS != code) break;
code = nodesListMakeStrictAppend(&pPassThroughCols, pClone);
if (TSDB_CODE_SUCCESS != code) {
nodesDestroyNode(pClone);
break;
}
}
}
}
Comment thread
facetosea marked this conversation as resolved.

// indefinite rows functions and _select_values functions
code = nodesCollectFuncs(pSelect, SQL_CLAUSE_SELECT, NULL, fmIsVectorFunc, &pIdfRowsFunc->pFuncs);
if (TSDB_CODE_SUCCESS == code) {
code = nodesCollectFuncs(pSelect, SQL_CLAUSE_SELECT, NULL, fmIsVectorFunc, &pIdfRowsFunc->pFuncs);
}
if (TSDB_CODE_SUCCESS == code) {
code = rewriteExprsForSelect(pIdfRowsFunc->pFuncs, pSelect, SQL_CLAUSE_SELECT, NULL);
}
Expand All @@ -1709,6 +1735,26 @@ static int32_t createIndefRowsFuncLogicNode(SLogicPlanContext* pCxt, SSelectStmt
code = createColumnByRewriteExprs(pIdfRowsFunc->pFuncs, &pIdfRowsFunc->node.pTargets);
}

// Add pass-through columns: each node was cloned once into pPassThroughCols (to snapshot
// state before rewriteExprsForSelect). Clone again here because pFuncs takes ownership
// and pPassThroughCols is destroyed separately.
if (TSDB_CODE_SUCCESS == code && NULL != pPassThroughCols) {
SNode* pNode = NULL;
FOREACH(pNode, pPassThroughCols) {
SNode* pClone = NULL;
code = nodesCloneNode(pNode, &pClone);
if (TSDB_CODE_SUCCESS != code) break;
code = nodesListMakeStrictAppend(&pIdfRowsFunc->pFuncs, pClone);
if (TSDB_CODE_SUCCESS != code) {
nodesDestroyNode(pClone);
break;
}
code = createColumnByRewriteExpr(pClone, &pIdfRowsFunc->node.pTargets);
if (TSDB_CODE_SUCCESS != code) break;
}
}
nodesDestroyList(pPassThroughCols);

if (TSDB_CODE_SUCCESS == code) {
*pLogicNode = (SLogicNode*)pIdfRowsFunc;
} else {
Expand Down
77 changes: 72 additions & 5 deletions source/libs/planner/src/planOptimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -4545,6 +4545,9 @@ static int32_t rewriteTailOptCreateSort(SIndefRowsFuncLogicNode* pIndef, SLogicN
SFunctionNode* pTail = NULL;
SNode* pFunc = NULL;
FOREACH(pFunc, pIndef->pFuncs) {
if (QUERY_NODE_FUNCTION != nodeType(pFunc)) {
continue;
}
if (FUNCTION_TYPE_TAIL == ((SFunctionNode*)pFunc)->funcType) {
pTail = (SFunctionNode*)pFunc;
break;
Expand Down Expand Up @@ -4597,14 +4600,28 @@ static int32_t rewriteTailOptCreateProject(SIndefRowsFuncLogicNode* pIndef, SLog
SNode* pFunc = NULL;
FOREACH(pFunc, pIndef->pFuncs) {
SNode* pNew = NULL;
code = rewriteTailOptCreateProjectExpr((SFunctionNode*)pFunc, &pNew);
if (TSDB_CODE_SUCCESS == code) {
code = nodesListMakeStrictAppend(&pProject->pProjections, pNew);
if (QUERY_NODE_FUNCTION != nodeType(pFunc)) {
code = nodesCloneNode(pFunc, &pNew);
if (TSDB_CODE_SUCCESS == code) {
tstrncpy(((SExprNode*)pNew)->aliasName, ((SExprNode*)pFunc)->aliasName, TSDB_COL_NAME_LEN);
code = nodesListMakeStrictAppend(&pProject->pProjections, pNew);
Comment thread
facetosea marked this conversation as resolved.
if (TSDB_CODE_SUCCESS != code) {
nodesDestroyNode(pNew);
}
}
} else {
code = rewriteTailOptCreateProjectExpr((SFunctionNode*)pFunc, &pNew);
if (TSDB_CODE_SUCCESS == code) {
code = nodesListMakeStrictAppend(&pProject->pProjections, pNew);
if (TSDB_CODE_SUCCESS != code) {
nodesDestroyNode(pNew);
}
}
}
if (TSDB_CODE_SUCCESS != code) {
break;
}
if (FUNCTION_TYPE_TAIL == ((SFunctionNode*)pFunc)->funcType) {
if (QUERY_NODE_FUNCTION == nodeType(pFunc) && FUNCTION_TYPE_TAIL == ((SFunctionNode*)pFunc)->funcType) {
pTail = (SFunctionNode*)pFunc;
}
}
Expand Down Expand Up @@ -4761,6 +4778,34 @@ static int32_t rewriteUniqueOptCreateFirstFunc(SFunctionNode* pSelectValue, SNod
return code;
}

// Wrap a column node with _select_value() to keep pAggFuncs function-only.
static int32_t rewriteUniqueOptCreateSelectValueFunc(SNode* pCol, SNode** ppNode) {
SFunctionNode* pFunc = NULL;
int32_t code = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pFunc);
if (NULL == pFunc) {
return code;
}

tstrncpy(pFunc->functionName, "_select_value", TSDB_FUNC_NAME_LEN);
tstrncpy(pFunc->node.aliasName, ((SExprNode*)pCol)->aliasName, TSDB_COL_NAME_LEN);
pFunc->node.resType = ((SExprNode*)pCol)->resType;
SNode* pNew = NULL;
code = nodesCloneNode(pCol, &pNew);
if (TSDB_CODE_SUCCESS == code) {
code = nodesListMakeStrictAppend(&pFunc->pParameterList, pNew);
}
if (TSDB_CODE_SUCCESS == code) {
code = fmGetFuncInfo(pFunc, NULL, 0);
}

if (TSDB_CODE_SUCCESS != code) {
nodesDestroyNode((SNode*)pFunc);
return code;
}
*ppNode = (SNode*)pFunc;
return code;
}

static int32_t rewriteUniqueOptCreateAgg(SIndefRowsFuncLogicNode* pIndef, SLogicNode** pOutput) {
SAggLogicNode* pAgg = NULL;
int32_t code = nodesMakeNode(QUERY_NODE_LOGIC_PLAN_AGG, (SNode**)&pAgg);
Expand All @@ -4785,6 +4830,20 @@ static int32_t rewriteUniqueOptCreateAgg(SIndefRowsFuncLogicNode* pIndef, SLogic
SNode* pPrimaryKey = NULL;
SNode* pNode = NULL;
FOREACH(pNode, pIndef->pFuncs) {
if (QUERY_NODE_FUNCTION != nodeType(pNode)) {
// Pass-through column from coexisting select agg; wrap with _select_value
// to keep pAggFuncs function-only (downstream walkers cast to SFunctionNode).
SNode* pNew = NULL;
code = rewriteUniqueOptCreateSelectValueFunc(pNode, &pNew);
if (TSDB_CODE_SUCCESS == code) {
code = nodesListMakeStrictAppend(&pAgg->pAggFuncs, pNew);
Comment thread
facetosea marked this conversation as resolved.
if (TSDB_CODE_SUCCESS != code) {
nodesDestroyNode(pNew);
}
}
if (TSDB_CODE_SUCCESS != code) break;
Comment thread
facetosea marked this conversation as resolved.
continue;
Comment thread
facetosea marked this conversation as resolved.
}
SFunctionNode* pFunc = (SFunctionNode*)pNode;
SNode* pExpr = nodesListGetNode(pFunc->pParameterList, 0);
if (FUNCTION_TYPE_UNIQUE == pFunc->funcType) {
Expand Down Expand Up @@ -4874,9 +4933,17 @@ static int32_t rewriteUniqueOptCreateProject(SIndefRowsFuncLogicNode* pIndef, SL
SNode* pNode = NULL;
FOREACH(pNode, pIndef->pFuncs) {
SNode* pNew = NULL;
code = rewriteUniqueOptCreateProjectCol((SFunctionNode*)pNode, &pNew);
if (QUERY_NODE_FUNCTION != nodeType(pNode)) {
// Pass-through column node: clone directly as projection
code = nodesCloneNode(pNode, &pNew);
} else {
code = rewriteUniqueOptCreateProjectCol((SFunctionNode*)pNode, &pNew);
}
if (TSDB_CODE_SUCCESS == code) {
code = nodesListMakeStrictAppend(&pProject->pProjections, pNew);
if (TSDB_CODE_SUCCESS != code) {
nodesDestroyNode(pNew);
}
}
if (TSDB_CODE_SUCCESS != code) {
break;
Expand Down
4 changes: 3 additions & 1 deletion source/libs/planner/src/planPhysiCreater.c
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,9 @@ static EDealRes doSetSlotId(SNode* pNode, void* pContext) {
}
// pIndex is definitely not NULL, otherwise it is a bug
if (NULL == pIndex) {
planError("doSetSlotId failed, invalid slot name %s", name);
SColumnNode* pDbgCol = (SColumnNode*)pNode;
planError("doSetSlotId failed, invalid slot name %s, colName=%s, aliasName=%s, tableAlias=%s, hasRef=%d, hasDep=%d",
name, pDbgCol->colName, pDbgCol->node.aliasName, pDbgCol->tableAlias, pDbgCol->hasRef, pDbgCol->hasDep);
pCxt->errCode = TSDB_CODE_PLAN_SLOT_NOT_FOUND;
taosMemoryFree(name);
return DEAL_RES_ERROR;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def check_errors(self, dbname=DBNAME):
f"select stateduration(c1 ,'GT',1,True) from {dbname}.t1",
f"select stateduration(c1 ,'GT',1,1s) , count(c1) from {dbname}.t1",
f"select stateduration(c1 ,'GT',1,1s) , avg(c1) from {dbname}.t1",
f"select stateduration(c1 ,'GT',1,1s) , min(c1) from {dbname}.t1",
# f"select stateduration(c1 ,'GT',1,1s) , min(c1) from {dbname}.t1", # indef+select now allowed
f"select stateduration(c1 ,'GT',1,1s) , spread(c1) from {dbname}.t1",
f"select stateduration(c1 ,'GT',1,1s) , diff(c1) from {dbname}.t1",
]
Expand Down Expand Up @@ -235,7 +235,7 @@ def basic_stateduration_function(self, dbname=DBNAME):

# unique with aggregate function
tdSql.error(f"select stateduration(c6,'GT',1,1s) ,sum(c1) from {dbname}.ct1")
tdSql.error(f"select stateduration(c6,'GT',1,1s) ,max(c1) from {dbname}.ct1")
tdSql.query(f"select stateduration(c6,'GT',1,1s) ,max(c1) from {dbname}.ct1") # indef+select now allowed
tdSql.error(f"select stateduration(c6,'GT',1,1s) ,csum(c1) from {dbname}.ct1")
tdSql.error(f"select stateduration(c6,'GT',1,1s) ,count(c1) from {dbname}.ct1")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def check_errors(self, dbname="db"):
f"select tail(True) from {dbname}.t1",
f"select tail(c1,1) , count(c1) from {dbname}.t1",
f"select tail(c1,1) , avg(c1) from {dbname}.t1",
f"select tail(c1,1) , min(c1) from {dbname}.t1",
# f"select tail(c1,1) , min(c1) from {dbname}.t1", # indef+select now allowed
f"select tail(c1,1) , spread(c1) from {dbname}.t1",
f"select tail(c1,1) , diff(c1) from {dbname}.t1",
f"select tail from {dbname}.stb1 partition by tbname",
Expand All @@ -106,7 +106,7 @@ def check_errors(self, dbname="db"):
f"select tail(True) from {dbname}.stb1 partition by tbname",
f"select tail(c1,1) , count(c1) from {dbname}.stb1 partition by tbname",
f"select tail(c1,1) , avg(c1) from {dbname}.stb1 partition by tbname",
f"select tail(c1,1) , min(c1) from {dbname}.stb1 partition by tbname",
# f"select tail(c1,1) , min(c1) from {dbname}.stb1 partition by tbname", # indef+select now allowed
f"select tail(c1,1) , spread(c1) from {dbname}.stb1 partition by tbname",
f"select tail(c1,1) , diff(c1) from {dbname}.stb1 partition by tbname",
]
Expand Down Expand Up @@ -274,7 +274,7 @@ def basic_tail_function(self, dbname="db"):

# tail with aggregate function
tdSql.error(f"select tail(c1,10,10) ,sum(c1) from {dbname}.ct1")
tdSql.error(f"select tail(c1,10,10) ,max(c1) from {dbname}.ct1")
tdSql.query(f"select tail(c1,10,10) ,max(c1) from {dbname}.ct1") # indef+select now allowed
tdSql.error(f"select tail(c1,10,10) ,csum(c1) from {dbname}.ct1")
tdSql.error(f"select tail(c1,10,10) ,count(c1) from {dbname}.ct1")

Expand Down
Loading
Loading