cols: use aggfunc

This commit is contained in:
facetosea 2025-02-16 01:15:12 +08:00
parent 26fb867d4c
commit c4cc51b583
14 changed files with 61 additions and 56 deletions

View File

@ -276,14 +276,14 @@ typedef struct tExprNode {
int32_t num;
struct SFunctionNode *pFunctNode;
int32_t functionType;
int32_t bindTupleFuncIdx;
int32_t bindExprID;
} _function;
struct {
struct SNode *pRootNode;
} _optrRoot;
};
int32_t tupleFuncIdx;
int32_t relatedTo;
} tExprNode;
struct SScalarParam {

View File

@ -62,8 +62,8 @@ typedef struct SExprNode {
bool asParam;
bool asPosition;
int32_t projIdx;
int32_t bindTupleFuncIdx;
int32_t tupleFuncIdx;
int32_t relatedTo;
int32_t bindExprID;
} SExprNode;
typedef enum EColumnType {
@ -701,6 +701,7 @@ char* getFullJoinTypeString(EJoinType type, EJoinSubType stype);
int32_t mergeJoinConds(SNode** ppDst, SNode** ppSrc);
int32_t rewriteExprAliasName(SExprNode* pNode, int64_t num);
bool isRelatedToOtherExpr(SExprNode* pExpr);
#ifdef __cplusplus
}

View File

@ -397,7 +397,7 @@ static int32_t createDataBlockForEmptyInput(SOperatorInfo* pOperator, SSDataBloc
// if the last expression is a tuple function, we don't need to create a empty data block
int32_t lastExprIndex = pOperator->exprSupp.numOfExprs - 1;
if(pOperator->exprSupp.pExprInfo[lastExprIndex].pExpr->tupleFuncIdx > 0) {
if(pOperator->exprSupp.pExprInfo[lastExprIndex].pExpr->_function.bindExprID > 0) {
return TSDB_CODE_SUCCESS;
}

View File

@ -1992,10 +1992,10 @@ int32_t createExprFromOneNode(SExprInfo* pExp, SNode* pNode, int16_t slotId) {
code = TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
QUERY_CHECK_CODE(code, lino, _end);
}
if(type == QUERY_NODE_FUNCTION) {
pExp->pExpr->_function.bindTupleFuncIdx = ((SExprNode*)pNode)->bindTupleFuncIdx;
if (type == QUERY_NODE_FUNCTION) {
pExp->pExpr->_function.bindExprID = ((SExprNode*)pNode)->bindExprID;
}
pExp->pExpr->tupleFuncIdx = ((SExprNode*)pNode)->tupleFuncIdx;
pExp->pExpr->relatedTo = ((SExprNode*)pNode)->relatedTo;
_end:
if (code != TSDB_CODE_SUCCESS) {
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
@ -2091,7 +2091,7 @@ static int32_t setSelectValueColumnInfo(SqlFunctionCtx* pCtx, int32_t numOfOutpu
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->tupleFuncIdx;
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
@ -2134,7 +2134,7 @@ static int32_t setSelectValueColumnInfo(SqlFunctionCtx* pCtx, int32_t numOfOutpu
if (pValCtxArray == NULL) {
pValCtx[num++] = &pCtx[i];
} else {
int32_t bindFuncIndex = pCtx[i].pExpr->pExpr->_function.bindTupleFuncIdx; // start from index 1;
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;
}

View File

@ -443,8 +443,8 @@ int32_t createFunctionWithSrcFunc(const char* pName, const SFunctionNode* pSrcFu
return code;
}
resetOutputChangedFunc(*ppFunc, pSrcFunc);
(*ppFunc)->node.bindTupleFuncIdx = pSrcFunc->node.bindTupleFuncIdx;
(*ppFunc)->node.tupleFuncIdx = pSrcFunc->node.tupleFuncIdx;
(*ppFunc)->node.relatedTo = pSrcFunc->node.relatedTo;
(*ppFunc)->node.bindExprID = pSrcFunc->node.bindExprID;
return code;
}

View File

@ -106,8 +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(bindTupleFuncIdx);
COPY_SCALAR_FIELD(tupleFuncIdx);
COPY_SCALAR_FIELD(relatedTo);
COPY_SCALAR_FIELD(bindExprID);
return TSDB_CODE_SUCCESS;
}

View File

@ -139,10 +139,10 @@ static bool functionNodeEqual(const SFunctionNode* a, const SFunctionNode* b) {
COMPARE_STRING_FIELD(functionName);
COMPARE_NODE_LIST_FIELD(pParameterList);
if (a->funcType == FUNCTION_TYPE_SELECT_VALUE) {
if ((a->node.bindTupleFuncIdx != b->node.bindTupleFuncIdx)) return false;
if ((a->node.relatedTo != b->node.relatedTo)) return false;
} else {
// select cols(cols(first(c0), ts), first(c0) from meters;
if ((a->node.tupleFuncIdx != b->node.tupleFuncIdx)) {
if ((a->node.bindExprID != b->node.bindExprID)) {
return false;
}
}

View File

@ -670,10 +670,10 @@ static int32_t exprNodeToMsg(const void* pObj, STlvEncoder* pEncoder) {
const SExprNode* pNode = (const SExprNode*)pObj;
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->bindTupleFuncIdx);
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->tupleFuncIdx);
code = tlvEncodeI32(pEncoder, EXPR_CODE_TUPLE_FUNC_IDX, pNode->bindExprID);
}
return code;
}
@ -689,10 +689,10 @@ static int32_t msgToExprNode(STlvDecoder* pDecoder, void* pObj) {
code = tlvDecodeObjFromTlv(pTlv, msgToDataType, &pNode->resType);
break;
case EXPR_CODE_BIND_TUPLE_FUNC_IDX:
code = tlvDecodeI32(pTlv, &pNode->bindTupleFuncIdx);
code = tlvDecodeI32(pTlv, &pNode->relatedTo);
break;
case EXPR_CODE_TUPLE_FUNC_IDX:
code = tlvDecodeI32(pTlv, &pNode->tupleFuncIdx);
code = tlvDecodeI32(pTlv, &pNode->bindExprID);
break;
default:
break;
@ -709,10 +709,10 @@ static int32_t columnNodeInlineToMsg(const void* pObj, STlvEncoder* pEncoder) {
int32_t code = dataTypeInlineToMsg(&pNode->node.resType, pEncoder);
if (TSDB_CODE_SUCCESS == code) {
code = tlvEncodeValueI32(pEncoder, pNode->node.bindTupleFuncIdx);
code = tlvEncodeValueI32(pEncoder, pNode->node.relatedTo);
}
if (TSDB_CODE_SUCCESS == code) {
code = tlvEncodeValueI32(pEncoder, pNode->node.tupleFuncIdx);
code = tlvEncodeValueI32(pEncoder, pNode->node.bindExprID);
}
if (TSDB_CODE_SUCCESS == code) {
code = tlvEncodeValueU64(pEncoder, pNode->tableId);
@ -765,10 +765,10 @@ static int32_t msgToColumnNodeInline(STlvDecoder* pDecoder, void* pObj) {
int32_t code = msgToDataTypeInline(pDecoder, &pNode->node.resType);
if (TSDB_CODE_SUCCESS == code) {
code = tlvDecodeValueI32(pDecoder, &pNode->node.bindTupleFuncIdx);
code = tlvDecodeValueI32(pDecoder, &pNode->node.relatedTo);
}
if (TSDB_CODE_SUCCESS == code) {
code = tlvDecodeValueI32(pDecoder, &pNode->node.tupleFuncIdx);
code = tlvDecodeValueI32(pDecoder, &pNode->node.bindExprID);
}
if (TSDB_CODE_SUCCESS == code) {
code = tlvDecodeValueU64(pDecoder, &pNode->tableId);

View File

@ -3243,3 +3243,7 @@ int32_t nodesListDeduplicate(SNodeList** ppList) {
int32_t rewriteExprAliasName(SExprNode* pNode, int64_t num) {
return tsnprintf(pNode->aliasName, TSDB_COL_NAME_LEN, "expr_%ld", num);
}
bool isRelatedToOtherExpr(SExprNode* pExpr) {
return pExpr->relatedTo != 0;
}

View File

@ -1105,11 +1105,11 @@ static bool isForecastPseudoColumnFunc(const SNode* pNode) {
}
static bool isColsFunctionResult(const SNode* pNode) {
return ((nodesIsExprNode(pNode)) && ((SExprNode*)pNode)->bindTupleFuncIdx > 0);
return ((nodesIsExprNode(pNode)) && ((SExprNode*)pNode)->relatedTo > 0);
}
static bool isInvalidColsBindFunction(const SFunctionNode* pFunc) {
return (!fmIsSelectFunc(pFunc->funcId) && pFunc->node.tupleFuncIdx != 0);
return (!fmIsSelectFunc(pFunc->funcId) && pFunc->node.bindExprID != 0);
}
#ifdef BUILD_NO_CALL
@ -3582,8 +3582,8 @@ 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.bindTupleFuncIdx = ((SExprNode*)*pNode)->bindTupleFuncIdx;
pFunc->node.tupleFuncIdx = ((SExprNode*)*pNode)->tupleFuncIdx;
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);
@ -3894,7 +3894,7 @@ 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)) &&
((SExprNode*)*pNode)->bindTupleFuncIdx == 0) {
!isRelatedToOtherExpr((SExprNode*)*pNode)) {
return generateDealNodeErrMsg(pCxt, getGroupByErrorCode(pCxt), ((SExprNode*)(*pNode))->userAlias);
}
if (isWindowJoinStmt(pSelect) &&
@ -3903,7 +3903,7 @@ static EDealRes doCheckExprForGroupBy(SNode** pNode, void* pContext) {
return rewriteExprToGroupKeyFunc(pCxt, pNode);
}
if ((pSelect->hasOtherVectorFunc || !pSelect->hasSelectFunc) && ((SExprNode*)*pNode)->bindTupleFuncIdx == 0) {
if ((pSelect->hasOtherVectorFunc || !pSelect->hasSelectFunc) && !isRelatedToOtherExpr((SExprNode*)*pNode)) {
return generateDealNodeErrMsg(pCxt, getGroupByErrorCode(pCxt), ((SExprNode*)(*pNode))->userAlias);
}
@ -3983,7 +3983,7 @@ static EDealRes doCheckAggColCoexist(SNode** pNode, void* pContext) {
return rewriteExprToSelectTagFunc(pCxt->pTranslateCxt, pNode);
}
if ((isScanPseudoColumnFunc(*pNode) || QUERY_NODE_COLUMN == nodeType(*pNode)) &&
((!nodesIsExprNode(*pNode) || ((SExprNode*)*pNode)->bindTupleFuncIdx == 0))) {
((!nodesIsExprNode(*pNode) || !isRelatedToOtherExpr((SExprNode*)*pNode)))) {
pCxt->existCol = true;
}
return DEAL_RES_CONTINUE;
@ -5466,16 +5466,18 @@ static int32_t prepareColumnExpansion(STranslateContext* pCxt, ESqlClause clause
int32_t code = TSDB_CODE_SUCCESS;
if (clause == SQL_CLAUSE_SELECT) {
code = rewriteColsFunction(pCxt, &pSelect->pProjectionList, &pSelect->pProjectionBindList);
code = translateExprList(pCxt, pSelect->pProjectionBindList);
} else if (clause == SQL_CLAUSE_ORDER_BY) {
code = rewriteColsFunction(pCxt, &pSelect->pOrderByList, &pSelect->pProjectionBindList);
if (TSDB_CODE_SUCCESS == code) {
code = translateExprList(pCxt, pSelect->pProjectionBindList);
}
} else {
code =
generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_WRONG_VALUE_TYPE, "Invalid clause for column expansion");
}
if (TSDB_CODE_SUCCESS == code) {
code = translateExprList(pCxt, pSelect->pProjectionBindList);
}
if (pSelect->pProjectionBindList != NULL) {
pSelect->hasAggFuncs = true;
}
return code;
}
@ -7391,19 +7393,19 @@ static bool isMultiColsFuncNode(SNode* pNode) {
}
typedef struct SBindTupleFuncCxt {
int32_t bindTupleFuncIdx;
int32_t bindExprID;
} SBindTupleFuncCxt;
static EDealRes pushDownBindSelectFunc(SNode** pNode, void* pContext) {
SBindTupleFuncCxt* pCxt = pContext;
if (nodesIsExprNode(*pNode)) {
((SExprNode*)*pNode)->bindTupleFuncIdx = pCxt->bindTupleFuncIdx;
((SExprNode*)*pNode)->relatedTo = pCxt->bindExprID;
int32_t len = strlen(((SExprNode*)*pNode)->aliasName);
if (len + TSDB_COL_NAME_EXLEN >= TSDB_COL_NAME_LEN) {
parserError("%s The alias name is too long, the extra part will be truncated", __func__);
return DEAL_RES_ERROR;
} else {
tsnprintf(((SExprNode*)*pNode)->aliasName + len, TSDB_COL_NAME_EXLEN, ".%d", pCxt->bindTupleFuncIdx);
tsnprintf(((SExprNode*)*pNode)->aliasName + len, TSDB_COL_NAME_EXLEN, ".%d", pCxt->bindExprID);
}
SFunctionNode* pFunc = (SFunctionNode*)*pNode;
}
@ -7512,7 +7514,7 @@ static EDealRes rewriteSingleColsFunc(SNode** pNode, void* pContext) {
selectFuncIndex = selectFuncCount;
SNode* pNewNode = NULL;
code = nodesCloneNode(pSelectFunc, &pNewNode);
((SExprNode*)pNewNode)->tupleFuncIdx = selectFuncIndex;
((SExprNode*)pNewNode)->bindExprID = selectFuncIndex;
nodesListMakeStrictAppend(pCxt->selectFuncList, pNewNode);
}
@ -7595,7 +7597,7 @@ static int32_t rewriteColsFunction(STranslateContext* pCxt, SNodeList** nodeList
++selectFuncCount;
selectFuncIndex = selectFuncCount;
code = nodesCloneNode(pSelectFunc, &pNewNode);
((SExprNode*)pNewNode)->tupleFuncIdx = selectFuncIndex;
((SExprNode*)pNewNode)->bindExprID = selectFuncIndex;
nodesListMakeStrictAppend(selectFuncList, pNewNode);
}
// start from index 1, because the first parameter is select function which needn't to output.
@ -13905,10 +13907,6 @@ static int32_t extractQueryResultSchema(const SNodeList* pProjections, int32_t*
int32_t index = 0;
FOREACH(pNode, pProjections) {
SExprNode* pExpr = (SExprNode*)pNode;
if(pExpr->tupleFuncIdx != 0) {
*numOfCols -= 1;
continue;
}
if (TSDB_DATA_TYPE_NULL == pExpr->resType.type) {
(*pSchema)[index].type = TSDB_DATA_TYPE_VARCHAR;
(*pSchema)[index].bytes = VARSTR_HEADER_SIZE;

View File

@ -123,8 +123,8 @@ 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.bindTupleFuncIdx = ((SExprNode*)(*pNode))->bindTupleFuncIdx;
pCol->node.tupleFuncIdx = ((SExprNode*)(*pNode))->tupleFuncIdx;
pCol->node.relatedTo = ((SExprNode*)(*pNode))->relatedTo;
//pCol->node.bindExprID = ((SExprNode*)(*pNode))->bindExprID;
if (QUERY_NODE_FUNCTION == nodeType(pExpr)) {
setColumnInfo((SFunctionNode*)pExpr, pCol, pCxt->isPartitionBy);
}
@ -712,7 +712,7 @@ static SColumnNode* createColumnByExpr(const char* pStmtName, SExprNode* pExpr)
if (NULL != pStmtName) {
snprintf(pCol->tableAlias, sizeof(pCol->tableAlias), "%s", pStmtName);
}
pCol->node.bindTupleFuncIdx = pExpr->bindTupleFuncIdx;
pCol->node.relatedTo = pExpr->relatedTo;
return pCol;
}
@ -818,7 +818,7 @@ static int32_t addWinJoinPrimKeyToAggFuncs(SSelectStmt* pSelect, SNodeList** pLi
}
static int32_t createAggLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SLogicNode** pLogicNode) {
if (!pSelect->hasAggFuncs && NULL == pSelect->pGroupByList && !pSelect->pProjectionBindList) {
if (!pSelect->hasAggFuncs && NULL == pSelect->pGroupByList) {
return TSDB_CODE_SUCCESS;
}
@ -1598,9 +1598,6 @@ static int32_t createColumnByProjections(SLogicPlanContext* pCxt, const char* pS
SNode* pNode;
int32_t projIdx = 1;
FOREACH(pNode, pExprs) {
if (((SExprNode*)pNode)->tupleFuncIdx != 0) {
continue;
}
SColumnNode* pCol = createColumnByExpr(pStmtName, (SExprNode*)pNode);
if (TSDB_CODE_SUCCESS != (code = nodesListStrictAppend(pList, (SNode*)pCol))) {
nodesDestroyList(pList);

View File

@ -3606,8 +3606,7 @@ static int32_t eliminateProjOptimizeImpl(SOptimizeContext* pCxt, SLogicSubplan*
} else {
FOREACH(pProjection, pProjectNode->pProjections) {
FOREACH(pChildTarget, pChild->pTargets) {
if (0 == strcmp(((SColumnNode*)pProjection)->colName, ((SColumnNode*)pChildTarget)->colName)
&& ((SColumnNode*)pProjection)->node.tupleFuncIdx == 0) {
if (0 == strcmp(((SColumnNode*)pProjection)->colName, ((SColumnNode*)pChildTarget)->colName)) {
SNode* pNew = NULL;
code = nodesCloneNode(pChildTarget, &pNew);
if (TSDB_CODE_SUCCESS == code) {

View File

@ -79,8 +79,7 @@ static EDealRes doCreateColumn(SNode* pNode, void* pContext) {
}
}
}
pCol->node.bindTupleFuncIdx = pExpr->bindTupleFuncIdx;
pCol->node.tupleFuncIdx = pExpr->tupleFuncIdx;
pCol->node.relatedTo = pExpr->relatedTo;
return (TSDB_CODE_SUCCESS == nodesListStrictAppend(pCxt->pList, (SNode*)pCol) ? DEAL_RES_IGNORE_CHILD
: DEAL_RES_ERROR);
}

View File

@ -522,6 +522,12 @@ class TDTestCase:
tdSql.checkCols(2)
tdSql.checkData(0, 0, 3)
tdSql.checkData(0, 1, 1)
tdSql.query(f'select * from (select cols(last_row(c0), ts as t1, c1), cols(first(c0), ts as t2, c1 c21), first(c0) from test.meters where c0 < 4)')
tdSql.checkRows(1)
tdSql.checkCols(5)
tdSql.checkData(0, 1, 3)
tdSql.checkData(0, 3, 1)
tdSql.checkData(0, 4, 1)
tdSql.error(f'select c1 from (select cols(last_row(c0), ts as t1, c1), cols(first(c0), ts as t2, c1), first(c0) from test.meters where c0 < 4)')
# cols on system table
@ -966,11 +972,12 @@ class TDTestCase:
self.one_cols_1output_test()
self.multi_cols_output_test()
self.subquery_test()
#self.window_test()
self.window_test()
self.join_test()
self.stream_cols_test()
self.include_null_test()
def stop(self):
tdSql.close()
tdLog.success("%s successfully executed" % __file__)