cols function
This commit is contained in:
parent
92d287f322
commit
7964e5e6b7
|
@ -155,6 +155,7 @@ typedef enum EFunctionType {
|
||||||
FUNCTION_TYPE_FORECAST_LOW,
|
FUNCTION_TYPE_FORECAST_LOW,
|
||||||
FUNCTION_TYPE_FORECAST_HIGH,
|
FUNCTION_TYPE_FORECAST_HIGH,
|
||||||
FUNCTION_TYPE_FORECAST_ROWTS,
|
FUNCTION_TYPE_FORECAST_ROWTS,
|
||||||
|
FUNCTION_TYPE_COLS,
|
||||||
FUNCTION_TYPE_IROWTS_ORIGIN,
|
FUNCTION_TYPE_IROWTS_ORIGIN,
|
||||||
|
|
||||||
// internal function
|
// internal function
|
||||||
|
@ -208,6 +209,9 @@ typedef enum EFunctionType {
|
||||||
FUNCTION_TYPE_HYPERLOGLOG_STATE,
|
FUNCTION_TYPE_HYPERLOGLOG_STATE,
|
||||||
FUNCTION_TYPE_HYPERLOGLOG_STATE_MERGE,
|
FUNCTION_TYPE_HYPERLOGLOG_STATE_MERGE,
|
||||||
|
|
||||||
|
FUNCTION_TYPE_COLS_PARTIAL,
|
||||||
|
FUNCTION_TYPE_COLS_MERGE,
|
||||||
|
|
||||||
// geometry functions
|
// geometry functions
|
||||||
FUNCTION_TYPE_GEOM_FROM_TEXT = 4250,
|
FUNCTION_TYPE_GEOM_FROM_TEXT = 4250,
|
||||||
FUNCTION_TYPE_AS_TEXT,
|
FUNCTION_TYPE_AS_TEXT,
|
||||||
|
@ -295,6 +299,7 @@ bool fmisSelectGroupConstValueFunc(int32_t funcId);
|
||||||
bool fmIsElapsedFunc(int32_t funcId);
|
bool fmIsElapsedFunc(int32_t funcId);
|
||||||
bool fmIsDBUsageFunc(int32_t funcId);
|
bool fmIsDBUsageFunc(int32_t funcId);
|
||||||
bool fmIsRowTsOriginFunc(int32_t funcId);
|
bool fmIsRowTsOriginFunc(int32_t funcId);
|
||||||
|
bool fmIsSelectColsFunc(int32_t funcId);
|
||||||
|
|
||||||
void getLastCacheDataType(SDataType* pType, int32_t pkBytes);
|
void getLastCacheDataType(SDataType* pType, int32_t pkBytes);
|
||||||
int32_t createFunction(const char* pName, SNodeList* pParameterList, SFunctionNode** pFunc);
|
int32_t createFunction(const char* pName, SNodeList* pParameterList, SFunctionNode** pFunc);
|
||||||
|
|
|
@ -149,6 +149,7 @@ int32_t sampleScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarPara
|
||||||
int32_t tailScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput);
|
int32_t tailScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput);
|
||||||
int32_t uniqueScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput);
|
int32_t uniqueScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput);
|
||||||
int32_t modeScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput);
|
int32_t modeScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput);
|
||||||
|
int32_t colsScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -906,6 +906,7 @@ int32_t taosGetErrSize();
|
||||||
#define TSDB_CODE_PAR_INVALID_ANOMALY_WIN_OPT TAOS_DEF_ERROR_CODE(0, 0x2684)
|
#define TSDB_CODE_PAR_INVALID_ANOMALY_WIN_OPT TAOS_DEF_ERROR_CODE(0, 0x2684)
|
||||||
#define TSDB_CODE_PAR_INVALID_FORECAST_CLAUSE TAOS_DEF_ERROR_CODE(0, 0x2685)
|
#define TSDB_CODE_PAR_INVALID_FORECAST_CLAUSE TAOS_DEF_ERROR_CODE(0, 0x2685)
|
||||||
#define TSDB_CODE_PAR_INVALID_VGID_LIST TAOS_DEF_ERROR_CODE(0, 0x2686)
|
#define TSDB_CODE_PAR_INVALID_VGID_LIST TAOS_DEF_ERROR_CODE(0, 0x2686)
|
||||||
|
#define TSDB_CODE_PAR_INVALID_COLS_FUNCTION TAOS_DEF_ERROR_CODE(0, 0x2687)
|
||||||
#define TSDB_CODE_PAR_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x26FF)
|
#define TSDB_CODE_PAR_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x26FF)
|
||||||
|
|
||||||
//planner
|
//planner
|
||||||
|
|
|
@ -251,6 +251,11 @@ int32_t blockDBUsageSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo
|
||||||
int32_t blockDBUsageFunction(SqlFunctionCtx* pCtx);
|
int32_t blockDBUsageFunction(SqlFunctionCtx* pCtx);
|
||||||
int32_t blockDBUsageFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock);
|
int32_t blockDBUsageFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock);
|
||||||
|
|
||||||
|
bool getColsFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv);
|
||||||
|
int32_t colsFunction(SqlFunctionCtx* pCtx);
|
||||||
|
int32_t colsPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock);
|
||||||
|
int32_t colsCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -59,6 +59,7 @@ extern "C" {
|
||||||
#define FUNC_MGT_COUNT_LIKE_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(30) // funcs that should also return 0 when no rows found
|
#define FUNC_MGT_COUNT_LIKE_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(30) // funcs that should also return 0 when no rows found
|
||||||
#define FUNC_MGT_PROCESS_BY_ROW FUNC_MGT_FUNC_CLASSIFICATION_MASK(31)
|
#define FUNC_MGT_PROCESS_BY_ROW FUNC_MGT_FUNC_CLASSIFICATION_MASK(31)
|
||||||
#define FUNC_MGT_FORECAST_PC_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(32)
|
#define FUNC_MGT_FORECAST_PC_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(32)
|
||||||
|
#define FUNC_MGT_SELECT_COLS_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(33)
|
||||||
|
|
||||||
#define FUNC_MGT_TEST_MASK(val, mask) (((val) & (mask)) != 0)
|
#define FUNC_MGT_TEST_MASK(val, mask) (((val) & (mask)) != 0)
|
||||||
|
|
||||||
|
|
|
@ -1233,6 +1233,17 @@ static int32_t translateForecastConf(SFunctionNode* pFunc, char* pErrBuf, int32_
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t translateCols(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
|
||||||
|
pFunc->node.resType = (SDataType){.bytes = tDataTypes[TSDB_DATA_TYPE_FLOAT].bytes, .type = TSDB_DATA_TYPE_FLOAT};
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getColFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
|
||||||
|
SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static EFuncReturnRows forecastEstReturnRows(SFunctionNode* pFunc) { return FUNC_RETURN_ROWS_N; }
|
static EFuncReturnRows forecastEstReturnRows(SFunctionNode* pFunc) { return FUNC_RETURN_ROWS_N; }
|
||||||
|
|
||||||
static int32_t translateDiff(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
|
static int32_t translateDiff(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
|
||||||
|
@ -5641,7 +5652,44 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
||||||
.paramInfoPattern = 0,
|
.paramInfoPattern = 0,
|
||||||
.outputParaInfo = {.validDataType = FUNC_PARAM_SUPPORT_VARCHAR_TYPE}},
|
.outputParaInfo = {.validDataType = FUNC_PARAM_SUPPORT_VARCHAR_TYPE}},
|
||||||
.translateFunc = translateOutVarchar,
|
.translateFunc = translateOutVarchar,
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
.name = "cols",
|
||||||
|
.type = FUNCTION_TYPE_COLS,
|
||||||
|
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_SELECT_COLS_FUNC,
|
||||||
|
.translateFunc = translateCols,
|
||||||
|
.dynDataRequiredFunc = NULL,
|
||||||
|
.getEnvFunc = getColsFuncEnv,
|
||||||
|
.initFunc = functionSetup,
|
||||||
|
.processFunc = colsFunction,
|
||||||
|
.sprocessFunc = colsScalarFunction,
|
||||||
|
.pPartialFunc = "_cols_partial",
|
||||||
|
.pMergeFunc = "_cols_merge",
|
||||||
|
.finalizeFunc = NULL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "_cols_partial",
|
||||||
|
.type = FUNCTION_TYPE_COLS_PARTIAL,
|
||||||
|
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_SELECT_COLS_FUNC,
|
||||||
|
.translateFunc = translateCols,
|
||||||
|
.dynDataRequiredFunc = NULL,
|
||||||
|
.getEnvFunc = getColsFuncEnv,
|
||||||
|
.initFunc = functionSetup,
|
||||||
|
.processFunc = colsFunction,
|
||||||
|
.finalizeFunc = colsPartialFinalize,
|
||||||
|
.combineFunc = colsCombine,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "_cols_merge",
|
||||||
|
.type = FUNCTION_TYPE_COLS_MERGE,
|
||||||
|
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_SELECT_COLS_FUNC,
|
||||||
|
.translateFunc = translateOutFirstIn,
|
||||||
|
.getEnvFunc = getFirstLastFuncEnv,
|
||||||
|
.initFunc = functionSetup,
|
||||||
|
.processFunc = lastFunctionMerge,
|
||||||
|
.finalizeFunc = colsPartialFinalize,
|
||||||
|
.combineFunc = colsCombine,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|
|
@ -7194,3 +7194,77 @@ int32_t cachedLastRowFunction(SqlFunctionCtx* pCtx) {
|
||||||
SET_VAL(pResInfo, numOfElems, 1);
|
SET_VAL(pResInfo, numOfElems, 1);
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getColsFuncEnv(SFunctionNode* pFunc, SFuncExecEnv* pEnv) {
|
||||||
|
SColumnNode* pNode = (SColumnNode*)nodesListGetNode(pFunc->pParameterList, 0);
|
||||||
|
pEnv->calcMemSize = pNode->node.resType.bytes;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t colsFunction(SqlFunctionCtx* pCtx) {
|
||||||
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
|
SFunctionNode* pSelectFunc = ((SFunctionNode*)(pCtx[0].pExpr->pExpr->_function.pFunctNode->pParameterList->pHead->pNode));
|
||||||
|
|
||||||
|
SFuncExecFuncs selectExecFuncs;
|
||||||
|
code = fmGetFuncExecFuncs(pCtx->functionId, &selectExecFuncs);
|
||||||
|
if(TSDB_CODE_SUCCESS != code) {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
if(selectExecFuncs.process == NULL) {
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
return selectExecFuncs.process(pCtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t colsPartialFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
|
||||||
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
|
|
||||||
|
SResultRowEntryInfo* pEntryInfo = GET_RES_INFO(pCtx);
|
||||||
|
SFirstLastRes* pRes = GET_ROWCELL_INTERBUF(pEntryInfo);
|
||||||
|
|
||||||
|
int32_t resultBytes = getFirstLastInfoSize(pRes->bytes, pRes->pkBytes);
|
||||||
|
|
||||||
|
// todo check for failure
|
||||||
|
char* res = taosMemoryCalloc(resultBytes + VARSTR_HEADER_SIZE, sizeof(char));
|
||||||
|
if (NULL == res) {
|
||||||
|
return terrno;
|
||||||
|
}
|
||||||
|
(void)memcpy(varDataVal(res), pRes, resultBytes);
|
||||||
|
|
||||||
|
varDataSetLen(res, resultBytes);
|
||||||
|
|
||||||
|
int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
|
||||||
|
SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
|
||||||
|
if (NULL == pCol) {
|
||||||
|
taosMemoryFree(res);
|
||||||
|
return TSDB_CODE_OUT_OF_RANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pEntryInfo->numOfRes == 0) {
|
||||||
|
colDataSetNULL(pCol, pBlock->info.rows);
|
||||||
|
code = setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, pBlock->info.rows);
|
||||||
|
} else {
|
||||||
|
code = colDataSetVal(pCol, pBlock->info.rows, res, false);
|
||||||
|
if (TSDB_CODE_SUCCESS != code) {
|
||||||
|
taosMemoryFree(res);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
code = setSelectivityValue(pCtx, pBlock, &pRes->pos, pBlock->info.rows);
|
||||||
|
}
|
||||||
|
taosMemoryFree(res);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t colsCombine(SqlFunctionCtx* pDestCtx, SqlFunctionCtx* pSourceCtx) {
|
||||||
|
SResultRowEntryInfo* pDResInfo = GET_RES_INFO(pDestCtx);
|
||||||
|
SFirstLastRes* pDBuf = GET_ROWCELL_INTERBUF(pDResInfo);
|
||||||
|
int32_t bytes = pDBuf->bytes;
|
||||||
|
|
||||||
|
SResultRowEntryInfo* pSResInfo = GET_RES_INFO(pSourceCtx);
|
||||||
|
SFirstLastRes* pSBuf = GET_ROWCELL_INTERBUF(pSResInfo);
|
||||||
|
|
||||||
|
pDBuf->hasResult = firstLastTransferInfoImpl(pSBuf, pDBuf, false);
|
||||||
|
pDResInfo->numOfRes = TMAX(pDResInfo->numOfRes, pSResInfo->numOfRes);
|
||||||
|
pDResInfo->isNullRes &= pSResInfo->isNullRes;
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
|
@ -173,6 +173,8 @@ bool fmIsScalarFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC
|
||||||
|
|
||||||
bool fmIsVectorFunc(int32_t funcId) { return !fmIsScalarFunc(funcId) && !fmIsPseudoColumnFunc(funcId); }
|
bool fmIsVectorFunc(int32_t funcId) { return !fmIsScalarFunc(funcId) && !fmIsPseudoColumnFunc(funcId); }
|
||||||
|
|
||||||
|
bool fmIsSelectColsFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MGT_SELECT_COLS_FUNC); }
|
||||||
|
|
||||||
bool fmIsSelectFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MGT_SELECT_FUNC); }
|
bool fmIsSelectFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MGT_SELECT_FUNC); }
|
||||||
|
|
||||||
bool fmIsTimelineFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MGT_TIMELINE_FUNC); }
|
bool fmIsTimelineFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MGT_TIMELINE_FUNC); }
|
||||||
|
|
|
@ -170,6 +170,7 @@ SNode* createInterpTimeAround(SAstCreateContext* pCxt, SNode* pTimepoint, SN
|
||||||
SNode* createWhenThenNode(SAstCreateContext* pCxt, SNode* pWhen, SNode* pThen);
|
SNode* createWhenThenNode(SAstCreateContext* pCxt, SNode* pWhen, SNode* pThen);
|
||||||
SNode* createCaseWhenNode(SAstCreateContext* pCxt, SNode* pCase, SNodeList* pWhenThenList, SNode* pElse);
|
SNode* createCaseWhenNode(SAstCreateContext* pCxt, SNode* pCase, SNodeList* pWhenThenList, SNode* pElse);
|
||||||
SNode* createAlterSingleTagColumnNode(SAstCreateContext* pCtx, SToken* token, SNode* pVal);
|
SNode* createAlterSingleTagColumnNode(SAstCreateContext* pCtx, SToken* token, SNode* pVal);
|
||||||
|
SNode* createColsFunctionNode(SAstCreateContext* pCxt, SNode* pFunc, SNodeList* pList);
|
||||||
|
|
||||||
SNode* addWhereClause(SAstCreateContext* pCxt, SNode* pStmt, SNode* pWhere);
|
SNode* addWhereClause(SAstCreateContext* pCxt, SNode* pStmt, SNode* pWhere);
|
||||||
SNode* addPartitionByClause(SAstCreateContext* pCxt, SNode* pStmt, SNodeList* pPartitionByList);
|
SNode* addPartitionByClause(SAstCreateContext* pCxt, SNode* pStmt, SNodeList* pPartitionByList);
|
||||||
|
@ -329,6 +330,7 @@ SNode* createDropTSMAStmt(SAstCreateContext* pCxt, bool ignoreNotExists, SNode*
|
||||||
SNode* createShowCreateTSMAStmt(SAstCreateContext* pCxt, SNode* pRealTable);
|
SNode* createShowCreateTSMAStmt(SAstCreateContext* pCxt, SNode* pRealTable);
|
||||||
SNode* createShowTSMASStmt(SAstCreateContext* pCxt, SNode* dbName);
|
SNode* createShowTSMASStmt(SAstCreateContext* pCxt, SNode* dbName);
|
||||||
SNode* createShowDiskUsageStmt(SAstCreateContext* pCxt, SNode* dbName, ENodeType type);
|
SNode* createShowDiskUsageStmt(SAstCreateContext* pCxt, SNode* dbName, ENodeType type);
|
||||||
|
SNodeList* createColsFuncParamNodeList(SAstCreateContext* pCxt, SNode* pFuncNode, SNodeList* pNodeList, SToken* pAlias);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -1249,6 +1249,7 @@ pseudo_column(A) ::= IROWTS_ORIGIN(B).
|
||||||
|
|
||||||
function_expression(A) ::= function_name(B) NK_LP expression_list(C) NK_RP(D). { A = createRawExprNodeExt(pCxt, &B, &D, createFunctionNode(pCxt, &B, C)); }
|
function_expression(A) ::= function_name(B) NK_LP expression_list(C) NK_RP(D). { A = createRawExprNodeExt(pCxt, &B, &D, createFunctionNode(pCxt, &B, C)); }
|
||||||
function_expression(A) ::= star_func(B) NK_LP star_func_para_list(C) NK_RP(D). { A = createRawExprNodeExt(pCxt, &B, &D, createFunctionNode(pCxt, &B, C)); }
|
function_expression(A) ::= star_func(B) NK_LP star_func_para_list(C) NK_RP(D). { A = createRawExprNodeExt(pCxt, &B, &D, createFunctionNode(pCxt, &B, C)); }
|
||||||
|
function_expression(A) ::= cols_func(B) NK_LP cols_func_para_list(C) NK_RP(D). { A = createRawExprNodeExt(pCxt, &B, &D, createFunctionNode(pCxt, &B, C)); }
|
||||||
function_expression(A) ::=
|
function_expression(A) ::=
|
||||||
CAST(B) NK_LP expr_or_subquery(C) AS type_name(D) NK_RP(E). { A = createRawExprNodeExt(pCxt, &B, &E, createCastFunctionNode(pCxt, releaseRawExprNode(pCxt, C), D)); }
|
CAST(B) NK_LP expr_or_subquery(C) AS type_name(D) NK_RP(E). { A = createRawExprNodeExt(pCxt, &B, &E, createCastFunctionNode(pCxt, releaseRawExprNode(pCxt, C), D)); }
|
||||||
function_expression(A) ::=
|
function_expression(A) ::=
|
||||||
|
@ -1311,6 +1312,23 @@ star_func(A) ::= FIRST(B).
|
||||||
star_func(A) ::= LAST(B). { A = B; }
|
star_func(A) ::= LAST(B). { A = B; }
|
||||||
star_func(A) ::= LAST_ROW(B). { A = B; }
|
star_func(A) ::= LAST_ROW(B). { A = B; }
|
||||||
|
|
||||||
|
%type cols_func { SToken }
|
||||||
|
%destructor cols_func { }
|
||||||
|
cols_func(A) ::= COLS(B). { A = B; }
|
||||||
|
|
||||||
|
%type cols_func_para_list { SNodeList* }
|
||||||
|
%destructor cols_func_para_list { nodesDestroyList($$); }
|
||||||
|
cols_func_para_list(A) ::= function_expression(B) NK_COMMA cols_func_expression_list(C). { A = createColsFuncParamNodeList(pCxt, B, C, NULL); }
|
||||||
|
|
||||||
|
cols_func_expression(A) ::= expr_or_subquery(B). { A = releaseRawExprNode(pCxt, B); }
|
||||||
|
cols_func_expression(A) ::= expr_or_subquery(B) column_alias(C). { A = setProjectionAlias(pCxt, releaseRawExprNode(pCxt, B), &C);}
|
||||||
|
cols_func_expression(A) ::= expr_or_subquery(B) AS column_alias(C). { A = setProjectionAlias(pCxt, releaseRawExprNode(pCxt, B), &C);}
|
||||||
|
|
||||||
|
%type cols_func_expression_list { SNodeList* }
|
||||||
|
%destructor cols_func_expression_list { nodesDestroyList($$); }
|
||||||
|
cols_func_expression_list(A) ::= cols_func_expression(B). { A = createNodeList(pCxt, B); }
|
||||||
|
cols_func_expression_list(A) ::= cols_func_expression_list(B) NK_COMMA cols_func_expression(C). { A = addNodeToList(pCxt, B, C); }
|
||||||
|
|
||||||
%type star_func_para_list { SNodeList* }
|
%type star_func_para_list { SNodeList* }
|
||||||
%destructor star_func_para_list { nodesDestroyList($$); }
|
%destructor star_func_para_list { nodesDestroyList($$); }
|
||||||
star_func_para_list(A) ::= NK_STAR(B). { A = createNodeList(pCxt, createColumnNode(pCxt, NULL, &B)); }
|
star_func_para_list(A) ::= NK_STAR(B). { A = createNodeList(pCxt, createColumnNode(pCxt, NULL, &B)); }
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
|
|
||||||
|
#include "nodes.h"
|
||||||
#include "parAst.h"
|
#include "parAst.h"
|
||||||
#include "parUtil.h"
|
#include "parUtil.h"
|
||||||
#include "tglobal.h"
|
#include "tglobal.h"
|
||||||
|
@ -356,6 +357,32 @@ SToken getTokenFromRawExprNode(SAstCreateContext* pCxt, SNode* pNode) {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SNodeList* createColsFuncParamNodeList(SAstCreateContext* pCxt, SNode* pNode, SNodeList* pNodeList, SToken* pAlias) {
|
||||||
|
CHECK_PARSER_STATUS(pCxt);
|
||||||
|
if (NULL == pNode || QUERY_NODE_RAW_EXPR != nodeType(pNode)) {
|
||||||
|
pCxt->errCode = TSDB_CODE_PAR_SYNTAX_ERROR;
|
||||||
|
}
|
||||||
|
CHECK_PARSER_STATUS(pCxt);
|
||||||
|
SRawExprNode* pRawExpr = (SRawExprNode*)pNode;
|
||||||
|
SNode* pFuncNode = pRawExpr->pNode;
|
||||||
|
if(pFuncNode->type != QUERY_NODE_FUNCTION) {
|
||||||
|
pCxt->errCode = TSDB_CODE_PAR_SYNTAX_ERROR;
|
||||||
|
}
|
||||||
|
CHECK_PARSER_STATUS(pCxt);
|
||||||
|
SNodeList* list = NULL;
|
||||||
|
pCxt->errCode = nodesMakeList(&list);
|
||||||
|
CHECK_MAKE_NODE(list);
|
||||||
|
pCxt->errCode = nodesListAppend(list, pFuncNode);
|
||||||
|
CHECK_PARSER_STATUS(pCxt);
|
||||||
|
pCxt->errCode = nodesListAppendList(list, pNodeList);
|
||||||
|
return list;
|
||||||
|
|
||||||
|
_err:
|
||||||
|
nodesDestroyNode(pFuncNode);
|
||||||
|
nodesDestroyList(pNodeList);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
SNodeList* createNodeList(SAstCreateContext* pCxt, SNode* pNode) {
|
SNodeList* createNodeList(SAstCreateContext* pCxt, SNode* pNode) {
|
||||||
CHECK_PARSER_STATUS(pCxt);
|
CHECK_PARSER_STATUS(pCxt);
|
||||||
SNodeList* list = NULL;
|
SNodeList* list = NULL;
|
||||||
|
@ -1150,6 +1177,24 @@ _err:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SNode* createColsFunctionNode(SAstCreateContext* pCxt, SNode* pColFunc, SNodeList* pExpr){
|
||||||
|
SFunctionNode* func = NULL;
|
||||||
|
CHECK_PARSER_STATUS(pCxt);
|
||||||
|
pCxt->errCode = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&func);
|
||||||
|
CHECK_MAKE_NODE(func);
|
||||||
|
strcpy(func->functionName, "cols");
|
||||||
|
pCxt->errCode = nodesListMakeAppend(&func->pParameterList, pColFunc);
|
||||||
|
CHECK_PARSER_STATUS(pCxt);
|
||||||
|
pCxt->errCode = nodesListMakeStrictAppendList(&func->pParameterList, pExpr);
|
||||||
|
CHECK_PARSER_STATUS(pCxt);
|
||||||
|
return (SNode*)func;
|
||||||
|
_err:
|
||||||
|
nodesDestroyNode((SNode*)func);
|
||||||
|
nodesDestroyNode(pColFunc);
|
||||||
|
nodesDestroyList(pExpr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
SNode* createSubstrFunctionNodeExt(SAstCreateContext* pCxt, SNode* pExpr, SNode* pExpr2, SNode* pExpr3) {
|
SNode* createSubstrFunctionNodeExt(SAstCreateContext* pCxt, SNode* pExpr, SNode* pExpr2, SNode* pExpr3) {
|
||||||
SFunctionNode* func = NULL;
|
SFunctionNode* func = NULL;
|
||||||
CHECK_PARSER_STATUS(pCxt);
|
CHECK_PARSER_STATUS(pCxt);
|
||||||
|
|
|
@ -355,6 +355,7 @@ static SKeyword keywordTable[] = {
|
||||||
{"FORCE_WINDOW_CLOSE", TK_FORCE_WINDOW_CLOSE},
|
{"FORCE_WINDOW_CLOSE", TK_FORCE_WINDOW_CLOSE},
|
||||||
{"DISK_INFO", TK_DISK_INFO},
|
{"DISK_INFO", TK_DISK_INFO},
|
||||||
{"AUTO", TK_AUTO},
|
{"AUTO", TK_AUTO},
|
||||||
|
{"COLS", TK_COLS},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|
|
@ -1097,6 +1097,10 @@ static bool isVectorFunc(const SNode* pNode) {
|
||||||
return (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsVectorFunc(((SFunctionNode*)pNode)->funcId));
|
return (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsVectorFunc(((SFunctionNode*)pNode)->funcId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isColsFunc(const SNode* pNode) {
|
||||||
|
return (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsSelectColsFunc(((SFunctionNode*)pNode)->funcId));
|
||||||
|
}
|
||||||
|
|
||||||
static bool isDistinctOrderBy(STranslateContext* pCxt) {
|
static bool isDistinctOrderBy(STranslateContext* pCxt) {
|
||||||
return (SQL_CLAUSE_ORDER_BY == pCxt->currClause && isSelectStmt(pCxt->pCurrStmt) &&
|
return (SQL_CLAUSE_ORDER_BY == pCxt->currClause && isSelectStmt(pCxt->pCurrStmt) &&
|
||||||
((SSelectStmt*)pCxt->pCurrStmt)->isDistinct);
|
((SSelectStmt*)pCxt->pCurrStmt)->isDistinct);
|
||||||
|
@ -2450,9 +2454,10 @@ static int32_t rewriteCountTbname(STranslateContext* pCxt, SFunctionNode* pCount
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hasInvalidFuncNesting(SNodeList* pParameterList) {
|
static bool hasInvalidFuncNesting(SFunctionNode* pFunc) {
|
||||||
|
if(pFunc->funcType == FUNCTION_TYPE_COLS) return false;
|
||||||
bool hasInvalidFunc = false;
|
bool hasInvalidFunc = false;
|
||||||
nodesWalkExprs(pParameterList, haveVectorFunction, &hasInvalidFunc);
|
nodesWalkExprs(pFunc->pParameterList, haveVectorFunction, &hasInvalidFunc);
|
||||||
return hasInvalidFunc;
|
return hasInvalidFunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2474,7 +2479,7 @@ static int32_t translateAggFunc(STranslateContext* pCxt, SFunctionNode* pFunc) {
|
||||||
if (beforeHaving(pCxt->currClause)) {
|
if (beforeHaving(pCxt->currClause)) {
|
||||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION);
|
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION);
|
||||||
}
|
}
|
||||||
if (hasInvalidFuncNesting(pFunc->pParameterList)) {
|
if (hasInvalidFuncNesting(pFunc)) {
|
||||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
|
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
|
||||||
}
|
}
|
||||||
// The auto-generated COUNT function in the DELETE statement is legal
|
// The auto-generated COUNT function in the DELETE statement is legal
|
||||||
|
@ -2518,7 +2523,7 @@ static int32_t translateIndefiniteRowsFunc(STranslateContext* pCxt, SFunctionNod
|
||||||
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC,
|
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC,
|
||||||
"%s function is not supported in window query or group query", pFunc->functionName);
|
"%s function is not supported in window query or group query", pFunc->functionName);
|
||||||
}
|
}
|
||||||
if (hasInvalidFuncNesting(pFunc->pParameterList)) {
|
if (hasInvalidFuncNesting(pFunc)) {
|
||||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
|
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
|
||||||
}
|
}
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
|
@ -2533,7 +2538,7 @@ static int32_t translateMultiRowsFunc(STranslateContext* pCxt, SFunctionNode* pF
|
||||||
((SSelectStmt*)pCxt->pCurrStmt)->hasMultiRowsFunc) {
|
((SSelectStmt*)pCxt->pCurrStmt)->hasMultiRowsFunc) {
|
||||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC);
|
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC);
|
||||||
}
|
}
|
||||||
if (hasInvalidFuncNesting(pFunc->pParameterList)) {
|
if (hasInvalidFuncNesting(pFunc)) {
|
||||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
|
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
|
||||||
}
|
}
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
|
@ -2564,7 +2569,7 @@ static int32_t translateInterpFunc(STranslateContext* pCxt, SFunctionNode* pFunc
|
||||||
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC,
|
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC,
|
||||||
"%s function is not supported in window query or group query", pFunc->functionName);
|
"%s function is not supported in window query or group query", pFunc->functionName);
|
||||||
}
|
}
|
||||||
if (hasInvalidFuncNesting(pFunc->pParameterList)) {
|
if (hasInvalidFuncNesting(pFunc)) {
|
||||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
|
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
|
||||||
}
|
}
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
|
@ -2630,7 +2635,7 @@ static int32_t translateForecastFunc(STranslateContext* pCxt, SFunctionNode* pFu
|
||||||
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC,
|
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC,
|
||||||
"%s function is not supported in window query or group query", pFunc->functionName);
|
"%s function is not supported in window query or group query", pFunc->functionName);
|
||||||
}
|
}
|
||||||
if (hasInvalidFuncNesting(pFunc->pParameterList)) {
|
if (hasInvalidFuncNesting(pFunc)) {
|
||||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
|
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_AGG_FUNC_NESTING);
|
||||||
}
|
}
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
|
@ -2860,6 +2865,9 @@ static int32_t calcSelectFuncNum(SFunctionNode* pFunc, int32_t currSelectFuncNum
|
||||||
if (fmIsCumulativeFunc(pFunc->funcId)) {
|
if (fmIsCumulativeFunc(pFunc->funcId)) {
|
||||||
return currSelectFuncNum > 0 ? currSelectFuncNum : 1;
|
return currSelectFuncNum > 0 ? currSelectFuncNum : 1;
|
||||||
}
|
}
|
||||||
|
if(fmIsSelectColsFunc(pFunc->funcId)) {
|
||||||
|
return currSelectFuncNum;
|
||||||
|
}
|
||||||
return currSelectFuncNum + ((fmIsMultiResFunc(pFunc->funcId) && !fmIsLastRowFunc(pFunc->funcId))
|
return currSelectFuncNum + ((fmIsMultiResFunc(pFunc->funcId) && !fmIsLastRowFunc(pFunc->funcId))
|
||||||
? getMultiResFuncNum(pFunc->pParameterList)
|
? getMultiResFuncNum(pFunc->pParameterList)
|
||||||
: 1);
|
: 1);
|
||||||
|
@ -3798,6 +3806,9 @@ static EDealRes doCheckExprForGroupBy(SNode** pNode, void* pContext) {
|
||||||
if (isVectorFunc(*pNode) && !isDistinctOrderBy(pCxt)) {
|
if (isVectorFunc(*pNode) && !isDistinctOrderBy(pCxt)) {
|
||||||
return DEAL_RES_IGNORE_CHILD;
|
return DEAL_RES_IGNORE_CHILD;
|
||||||
}
|
}
|
||||||
|
if (isColsFunc(*pNode)) {
|
||||||
|
return DEAL_RES_IGNORE_CHILD;
|
||||||
|
}
|
||||||
SNode* pGroupNode = NULL;
|
SNode* pGroupNode = NULL;
|
||||||
FOREACH(pGroupNode, getGroupByList(pCxt)) {
|
FOREACH(pGroupNode, getGroupByList(pCxt)) {
|
||||||
SNode* pActualNode = getGroupByNode(pGroupNode);
|
SNode* pActualNode = getGroupByNode(pGroupNode);
|
||||||
|
@ -3891,6 +3902,7 @@ static int32_t rewriteColsToSelectValFunc(STranslateContext* pCxt, SSelectStmt*
|
||||||
typedef struct CheckAggColCoexistCxt {
|
typedef struct CheckAggColCoexistCxt {
|
||||||
STranslateContext* pTranslateCxt;
|
STranslateContext* pTranslateCxt;
|
||||||
bool existCol;
|
bool existCol;
|
||||||
|
bool hasColFunc;
|
||||||
SNodeList* pColList;
|
SNodeList* pColList;
|
||||||
} CheckAggColCoexistCxt;
|
} CheckAggColCoexistCxt;
|
||||||
|
|
||||||
|
@ -3899,6 +3911,10 @@ static EDealRes doCheckAggColCoexist(SNode** pNode, void* pContext) {
|
||||||
if (isVectorFunc(*pNode)) {
|
if (isVectorFunc(*pNode)) {
|
||||||
return DEAL_RES_IGNORE_CHILD;
|
return DEAL_RES_IGNORE_CHILD;
|
||||||
}
|
}
|
||||||
|
if(isColsFunc(*pNode)) {
|
||||||
|
pCxt->hasColFunc = true;
|
||||||
|
return DEAL_RES_IGNORE_CHILD;
|
||||||
|
}
|
||||||
SNode* pPartKey = NULL;
|
SNode* pPartKey = NULL;
|
||||||
bool partionByTbname = false;
|
bool partionByTbname = false;
|
||||||
if (fromSingleTable(((SSelectStmt*)pCxt->pTranslateCxt->pCurrStmt)->pFromTable) ||
|
if (fromSingleTable(((SSelectStmt*)pCxt->pTranslateCxt->pCurrStmt)->pFromTable) ||
|
||||||
|
@ -3977,7 +3993,7 @@ static int32_t checkAggColCoexist(STranslateContext* pCxt, SSelectStmt* pSelect)
|
||||||
if (!pSelect->onlyHasKeepOrderFunc) {
|
if (!pSelect->onlyHasKeepOrderFunc) {
|
||||||
pSelect->timeLineResMode = TIME_LINE_NONE;
|
pSelect->timeLineResMode = TIME_LINE_NONE;
|
||||||
}
|
}
|
||||||
CheckAggColCoexistCxt cxt = {.pTranslateCxt = pCxt, .existCol = false};
|
CheckAggColCoexistCxt cxt = {.pTranslateCxt = pCxt, .existCol = false, .hasColFunc = false};
|
||||||
nodesRewriteExprs(pSelect->pProjectionList, doCheckAggColCoexist, &cxt);
|
nodesRewriteExprs(pSelect->pProjectionList, doCheckAggColCoexist, &cxt);
|
||||||
if (!pSelect->isDistinct) {
|
if (!pSelect->isDistinct) {
|
||||||
nodesRewriteExprs(pSelect->pOrderByList, doCheckAggColCoexist, &cxt);
|
nodesRewriteExprs(pSelect->pOrderByList, doCheckAggColCoexist, &cxt);
|
||||||
|
@ -3989,6 +4005,9 @@ static int32_t checkAggColCoexist(STranslateContext* pCxt, SSelectStmt* pSelect)
|
||||||
if (cxt.existCol) {
|
if (cxt.existCol) {
|
||||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_SINGLE_GROUP);
|
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_SINGLE_GROUP);
|
||||||
}
|
}
|
||||||
|
if (cxt.hasColFunc) {
|
||||||
|
return rewriteColsToSelectValFunc(pCxt, pSelect);
|
||||||
|
}
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5169,6 +5188,54 @@ static int32_t createMultiResFunc(SFunctionNode* pSrcFunc, SExprNode* pExpr, SNo
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t createMultiResColsFunc(SFunctionNode* pSrcFunc, SFunctionNode* pSelectFunc, SExprNode* pExpr, SNode** ppNodeOut) {
|
||||||
|
SFunctionNode* pFunc = NULL;
|
||||||
|
int32_t code = nodesMakeNode(QUERY_NODE_FUNCTION, (SNode**)&pFunc);
|
||||||
|
if (TSDB_CODE_SUCCESS != code) {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
code = nodesMakeList(&pFunc->pParameterList);
|
||||||
|
SNode* pClonedFuncNode = NULL;
|
||||||
|
if (TSDB_CODE_SUCCESS != (code = nodesCloneNode((SNode*)pSelectFunc, &pClonedFuncNode)) ||
|
||||||
|
TSDB_CODE_SUCCESS != (code = nodesListStrictAppend(pFunc->pParameterList, pClonedFuncNode))) {
|
||||||
|
nodesDestroyNode((SNode*)pFunc);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
SNode* pClonedExprNode = NULL;
|
||||||
|
if (TSDB_CODE_SUCCESS != (code = nodesCloneNode((SNode*)pExpr, &pClonedExprNode)) ||
|
||||||
|
TSDB_CODE_SUCCESS != (code = nodesListStrictAppend(pFunc->pParameterList, pClonedExprNode))) {
|
||||||
|
nodesDestroyNode((SNode*)pFunc);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
pFunc->node.resType = pExpr->resType;
|
||||||
|
pFunc->funcId = pSrcFunc->funcId;
|
||||||
|
pFunc->funcType = pSrcFunc->funcType;
|
||||||
|
strcpy(pFunc->functionName, pSrcFunc->functionName);
|
||||||
|
char buf[TSDB_FUNC_NAME_LEN + TSDB_TABLE_NAME_LEN + TSDB_COL_NAME_LEN + TSDB_NAME_DELIMITER_LEN + 3] = {0};
|
||||||
|
int32_t len = 0;
|
||||||
|
if(pExpr->asAlias) {
|
||||||
|
strncpy(pFunc->node.aliasName, pExpr->aliasName, TSDB_COL_NAME_LEN - 1);
|
||||||
|
strncpy(pFunc->node.userAlias, pExpr->userAlias, TSDB_COL_NAME_LEN - 1);
|
||||||
|
pFunc->node.asAlias = true;
|
||||||
|
} else if (QUERY_NODE_COLUMN == nodeType(pExpr)) {
|
||||||
|
SColumnNode* pCol = (SColumnNode*)pExpr;
|
||||||
|
len = tsnprintf(buf, sizeof(buf) - 1, "%s.%s", pCol->tableAlias, pCol->colName);
|
||||||
|
(void)taosHashBinary(buf, len);
|
||||||
|
strncpy(pFunc->node.aliasName, buf, TSDB_COL_NAME_LEN - 1);
|
||||||
|
len = tsnprintf(buf, sizeof(buf) - 1, "%s", pCol->colName);
|
||||||
|
strncpy(pFunc->node.userAlias, buf, TSDB_COL_NAME_LEN - 1);
|
||||||
|
} else {
|
||||||
|
len = tsnprintf(buf, sizeof(buf) - 1, "%s(%s)", pSrcFunc->functionName, pExpr->aliasName);
|
||||||
|
(void)taosHashBinary(buf, len);
|
||||||
|
strncpy(pFunc->node.aliasName, buf, TSDB_COL_NAME_LEN - 1);
|
||||||
|
len = tsnprintf(buf, sizeof(buf) - 1, "%s(%s)", pSrcFunc->functionName, pExpr->userAlias);
|
||||||
|
strncpy(pFunc->node.userAlias, buf, TSDB_COL_NAME_LEN - 1);
|
||||||
|
}
|
||||||
|
*ppNodeOut = (SNode*)pFunc;
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t createTableAllCols(STranslateContext* pCxt, SColumnNode* pCol, bool igTags, SNodeList** pOutput) {
|
static int32_t createTableAllCols(STranslateContext* pCxt, SColumnNode* pCol, bool igTags, SNodeList** pOutput) {
|
||||||
STableNode* pTable = NULL;
|
STableNode* pTable = NULL;
|
||||||
int32_t code = findTable(pCxt, pCol->tableAlias, &pTable);
|
int32_t code = findTable(pCxt, pCol->tableAlias, &pTable);
|
||||||
|
@ -7272,10 +7339,166 @@ static int32_t translateSelectWithoutFrom(STranslateContext* pCxt, SSelectStmt*
|
||||||
return translateExprList(pCxt, pSelect->pProjectionList);
|
return translateExprList(pCxt, pSelect->pProjectionList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct SHasMultiColsFuncCxt {
|
||||||
|
bool hasMultiColsFunc;
|
||||||
|
} SHasMultiColsFuncCxt;
|
||||||
|
|
||||||
|
static bool isMultiColsFunc(SFunctionNode* pFunc) {
|
||||||
|
if (strcasecmp(pFunc->functionName, "cols") != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return pFunc->pParameterList->length > 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EDealRes isMultiColsFuncNode(SNode** pNode, void* pContext) {
|
||||||
|
SHasMultiColsFuncCxt* pCxt = pContext;
|
||||||
|
if (QUERY_NODE_FUNCTION == nodeType(*pNode)) {
|
||||||
|
SFunctionNode* pFunc = (SFunctionNode*)*pNode;
|
||||||
|
if (isMultiColsFunc(pFunc)) {
|
||||||
|
pCxt->hasMultiColsFunc = true;
|
||||||
|
return DEAL_RES_END;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DEAL_RES_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hasMultiColsFuncInList(SNodeList* nodeList) {
|
||||||
|
SHasMultiColsFuncCxt pCxt = {false};
|
||||||
|
|
||||||
|
nodesRewriteExprs(nodeList, isMultiColsFuncNode, &pCxt);
|
||||||
|
|
||||||
|
return pCxt.hasMultiColsFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hasMultiColsFunc(SNode** pNode) {
|
||||||
|
SHasMultiColsFuncCxt pCxt = {false};
|
||||||
|
|
||||||
|
nodesRewriteExpr(pNode, isMultiColsFuncNode, &pCxt);
|
||||||
|
|
||||||
|
return pCxt.hasMultiColsFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t hasInvalidColsFunction(STranslateContext* pCxt, SNodeList* nodeList) {
|
||||||
|
SNode* pTmpNode = NULL;
|
||||||
|
FOREACH(pTmpNode, nodeList) {
|
||||||
|
if (QUERY_NODE_FUNCTION == nodeType(pTmpNode)) {
|
||||||
|
SFunctionNode* pFunc = (SFunctionNode*)pTmpNode;
|
||||||
|
if (pFunc->funcType == FUNCTION_TYPE_COLS) {
|
||||||
|
// cols function at here is valid.
|
||||||
|
} else {
|
||||||
|
if (hasMultiColsFuncInList(pFunc->pParameterList)) {
|
||||||
|
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_COLS_FUNCTION,
|
||||||
|
"Invalid cols function in function %s", pFunc->functionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (hasMultiColsFunc(&pTmpNode)) {
|
||||||
|
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_COLS_FUNCTION,
|
||||||
|
"Invalid cols function, can't be used at here");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool invalidColsAlias(SFunctionNode* pFunc) {
|
||||||
|
if (strcasecmp(pFunc->functionName, "cols") != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (pFunc->node.asAlias) {
|
||||||
|
if (pFunc->pParameterList->length > 2) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
SNode* pNode;
|
||||||
|
FOREACH(pNode, pFunc->pParameterList) {
|
||||||
|
SExprNode* pExpr = (SExprNode*)pNode;
|
||||||
|
if (pExpr->asAlias) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t rewriteColsFunction(STranslateContext* pCxt, SNodeList** nodeList) {
|
||||||
|
int32_t code = hasInvalidColsFunction(pCxt, *nodeList);
|
||||||
|
if (TSDB_CODE_SUCCESS != code) {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
bool needRewrite = false;
|
||||||
|
SNode* pTmpNode = NULL;
|
||||||
|
FOREACH(pTmpNode, *nodeList) {
|
||||||
|
if (QUERY_NODE_FUNCTION == nodeType(pTmpNode)) {
|
||||||
|
SFunctionNode* pFunc = (SFunctionNode*)pTmpNode;
|
||||||
|
if(invalidColsAlias(pFunc)) {
|
||||||
|
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_COLS_FUNCTION,
|
||||||
|
"Invalid using alias for cols function");
|
||||||
|
}
|
||||||
|
if (isMultiColsFunc(pFunc)) {
|
||||||
|
needRewrite = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SNodeList* pNewNodeList = NULL;
|
||||||
|
if (needRewrite) {
|
||||||
|
code = nodesMakeList(&pNewNodeList);
|
||||||
|
if (NULL == pNewNodeList) {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
FOREACH(pTmpNode, *nodeList) {
|
||||||
|
if (QUERY_NODE_FUNCTION == nodeType(pTmpNode)) {
|
||||||
|
SFunctionNode* pFunc = (SFunctionNode*)pTmpNode;
|
||||||
|
if (isMultiColsFunc(pFunc)) {
|
||||||
|
// start from index 1, because the first parameter is select function which needn't to output.
|
||||||
|
SFunctionNode* pSelectFunc = (SFunctionNode*)nodesListGetNode(pFunc->pParameterList, 0);
|
||||||
|
for (int i = 1; i < pFunc->pParameterList->length; ++i) {
|
||||||
|
SNode* pExpr = nodesListGetNode(pFunc->pParameterList, i);
|
||||||
|
SNode* pNewFunc = NULL;
|
||||||
|
code = createMultiResColsFunc(pFunc, pSelectFunc, (SExprNode*)pExpr, &pNewFunc);
|
||||||
|
if (TSDB_CODE_SUCCESS != code) goto _end;
|
||||||
|
code = nodesListMakeStrictAppend(&pNewNodeList, pNewFunc);
|
||||||
|
if (TSDB_CODE_SUCCESS != code) goto _end;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SNode* pNewNode = NULL;
|
||||||
|
code = nodesCloneNode(pTmpNode, &pNewNode);
|
||||||
|
if (TSDB_CODE_SUCCESS != code) goto _end;
|
||||||
|
code = nodesListMakeStrictAppend(&pNewNodeList, pNewNode);
|
||||||
|
if (TSDB_CODE_SUCCESS != code) goto _end;
|
||||||
|
}
|
||||||
|
nodesDestroyList(*nodeList);
|
||||||
|
*nodeList = pNewNodeList;
|
||||||
|
}
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
|
||||||
|
_end:
|
||||||
|
if (TSDB_CODE_SUCCESS != code) {
|
||||||
|
nodesDestroyList(pNewNodeList);
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t translateColsFunction(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
|
int32_t code = rewriteColsFunction(pCxt, &pSelect->pProjectionList);
|
||||||
|
if (code == TSDB_CODE_SUCCESS) {
|
||||||
|
code = rewriteColsFunction(pCxt, &pSelect->pOrderByList);
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t translateSelectFrom(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
static int32_t translateSelectFrom(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
pCxt->pCurrStmt = (SNode*)pSelect;
|
pCxt->pCurrStmt = (SNode*)pSelect;
|
||||||
pCxt->dual = false;
|
pCxt->dual = false;
|
||||||
int32_t code = translateFrom(pCxt, &pSelect->pFromTable);
|
int32_t code = translateFrom(pCxt, &pSelect->pFromTable);
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = translateColsFunction(pCxt, pSelect);
|
||||||
|
}
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
pSelect->precision = ((STableNode*)pSelect->pFromTable)->precision;
|
pSelect->precision = ((STableNode*)pSelect->pFromTable)->precision;
|
||||||
code = translateWhere(pCxt, pSelect);
|
code = translateWhere(pCxt, pSelect);
|
||||||
|
|
|
@ -4588,3 +4588,7 @@ int32_t uniqueScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarPara
|
||||||
int32_t modeScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput) {
|
int32_t modeScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput) {
|
||||||
return selectScalarFunction(pInput, inputNum, pOutput);
|
return selectScalarFunction(pInput, inputNum, pOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t colsScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput) {
|
||||||
|
return selectScalarFunction(pInput, inputNum, pOutput);
|
||||||
|
}
|
||||||
|
|
|
@ -748,8 +748,9 @@ TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_ANOMALY_WIN_TYPE, "ANOMALY_WINDOW only
|
||||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_ANOMALY_WIN_COL, "ANOMALY_WINDOW not support on tag column")
|
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_ANOMALY_WIN_COL, "ANOMALY_WINDOW not support on tag column")
|
||||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_ANOMALY_WIN_OPT, "ANOMALY_WINDOW option should include algo field")
|
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_ANOMALY_WIN_OPT, "ANOMALY_WINDOW option should include algo field")
|
||||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_FORECAST_CLAUSE, "Invalid forecast clause")
|
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_FORECAST_CLAUSE, "Invalid forecast clause")
|
||||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_REGULAR_EXPRESSION_ERROR, "Syntax error in regular expression")
|
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_REGULAR_EXPRESSION_ERROR, "Syntax error in regular expression")
|
||||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_VGID_LIST, "Invalid vgid list")
|
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_VGID_LIST, "Invalid vgid list")
|
||||||
|
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INVALID_COLS_FUNCTION, "Invalid cols function")
|
||||||
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INTERNAL_ERROR, "Parser internal error")
|
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INTERNAL_ERROR, "Parser internal error")
|
||||||
|
|
||||||
//planner
|
//planner
|
||||||
|
|
|
@ -1084,6 +1084,10 @@
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/odbc.py
|
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/odbc.py
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/fill_with_group.py
|
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/fill_with_group.py
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/state_window.py -Q 3
|
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/state_window.py -Q 3
|
||||||
|
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/cols_function.py
|
||||||
|
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/cols_function.py -Q 2
|
||||||
|
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/cols_function.py -Q 3
|
||||||
|
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/cols_function.py -Q 4
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 99-TDcase/TD-21561.py -Q 4
|
,,y,system-test,./pytest.sh python3 ./test.py -f 99-TDcase/TD-21561.py -Q 4
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 99-TDcase/TD-20582.py
|
,,y,system-test,./pytest.sh python3 ./test.py -f 99-TDcase/TD-20582.py
|
||||||
,,n,system-test,python3 ./test.py -f 5-taos-tools/taosbenchmark/insertMix.py -N 3
|
,,n,system-test,python3 ./test.py -f 5-taos-tools/taosbenchmark/insertMix.py -N 3
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
from util.log import *
|
||||||
|
from util.cases import *
|
||||||
|
from util.sql import *
|
||||||
|
from util.common import *
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
class TDTestCase:
|
||||||
|
def init(self, conn, logSql, replicaVar=1):
|
||||||
|
self.replicaVar = int(replicaVar)
|
||||||
|
tdLog.debug("start to execute %s" % __file__)
|
||||||
|
tdSql.init(conn.cursor())
|
||||||
|
|
||||||
|
self.dbname = 'test'
|
||||||
|
|
||||||
|
def create_test_data(self):
|
||||||
|
tdLog.info("create test data")
|
||||||
|
tdLog.info("taosBenchmark -y -t 10 -n 100 -b INT,FLOAT,NCHAR,BOOL")
|
||||||
|
os.system("taosBenchmark -y -t 10 -n 100 -b INT,FLOAT,NCHAR,BOOL")
|
||||||
|
|
||||||
|
tdSql.execute('use test')
|
||||||
|
tdSql.execute(f'Create table {self.dbname}.normal_table (ts timestamp, c0 int, c1 float, c2 nchar(30), c3 bool)')
|
||||||
|
tdSql.execute(f'insert into {self.dbname}.normal_table (select * from {self.dbname}.d0)')
|
||||||
|
|
||||||
|
def one_cols_1output_test(self):
|
||||||
|
tdLog.info("one_cols_1output_test")
|
||||||
|
tdSql.query(f'select cols(last(ts), ts) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(last(ts), ts) as t1 from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(last(ts), ts as t1) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(last(ts), c0) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(last(ts), c1) from {self.dbname}.meters group by tbname')
|
||||||
|
|
||||||
|
|
||||||
|
tdSql.query(f'select cols(last(ts+1), ts) as t1 from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(last(ts+1), ts+2 as t1) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(last(ts+1), c0+10) from {self.dbname}.meters')
|
||||||
|
|
||||||
|
|
||||||
|
def one_cols_multi_output_test(self):
|
||||||
|
tdLog.info("one_cols_1output_test")
|
||||||
|
tdSql.query(f'select cols(last(ts), ts, c0) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(last(ts), ts, c0) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(last(ts), ts as time, c0 cc) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(last(ts), c0, c1, c2, c3) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(last(c1), ts) from {self.dbname}.meters group by tbname')
|
||||||
|
|
||||||
|
|
||||||
|
tdSql.query(f'select cols(max(c0), ts) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(min(c1), ts, c0) from {self.dbname}.meters')
|
||||||
|
|
||||||
|
tdSql.query(f'select cols(last(ts), ts, c0), count(1) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select count(1), cols(last(ts), ts, c0), min(c0) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(last(ts), ts, c0), count(1) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(last(ts), ts as time, c0 cc), count(1) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(last(ts), c0, c1, c2, c3), count(1) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(last(c1), ts), count(1) from {self.dbname}.meters group by tbname')
|
||||||
|
|
||||||
|
|
||||||
|
tdSql.query(f'select cols(max(c0), ts), count(1) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(min(c1), ts, c0), count(1) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select count(1), cols(max(c0), ts) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select max(c0), cols(max(c0), ts) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select max(c1), cols(max(c0), ts) from {self.dbname}.meters')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def multi_cols_output_test(self):
|
||||||
|
tdLog.info("multi_cols_output_test")
|
||||||
|
tdSql.query(f'select cols(last(c0), ts, c1), cols(first(c0), ts, c1), count(1) from {self.dbname}.meters')
|
||||||
|
tdSql.query(f'select cols(last(c0), ts as t1, c1 as c11), cols(first(c0), ts as c2, c1 c21), count(1) from {self.dbname}.meters')
|
||||||
|
|
||||||
|
def parse_test(self):
|
||||||
|
tdLog.info("parse test")
|
||||||
|
|
||||||
|
|
||||||
|
#** error sql **#
|
||||||
|
tdSql.error(f'select cols(ts) from {self.dbname}.meters group by tbname')
|
||||||
|
tdSql.error(f'select cols(ts) from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select last(cols(ts)) from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select last(cols(ts, ts)) from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select last(cols(ts, ts), ts) from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select last(cols(last(ts), ts), ts) from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select cols(last(ts), ts as t1) as t1 from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select cols(last(ts), ts, c0) t1 from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select cols(last(ts), ts t1) tt from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select cols(last(ts), c0 cc0, c1 cc1) cc from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select cols(last(ts), c0 as cc0) as cc from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select cols(ts) + 1 from {self.dbname}.meters group by tbname')
|
||||||
|
tdSql.error(f'select last(cols(ts)+1) from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select last(cols(ts+1, ts)) from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select last(cols(ts, ts), ts+1) from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select last(cols(last(ts+1), ts+1), ts) from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select cols(last(ts), ts+1 as t1) as t1 from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select cols(last(ts+1), ts, c0) t1 from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select cols(last(ts), ts t1) tt from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select cols(first(ts+1), c0+2 cc0, c1 cc1) cc from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select cols(last(ts)+1, c0+2 as cc0) as cc from {self.dbname}.meters')
|
||||||
|
|
||||||
|
tdSql.error(f'select cols(last(ts)+1, ts) from {self.dbname}.meters')
|
||||||
|
tdSql.error(f'select cols(last(ts)+10, c1+10) from {self.dbname}.meters group by tbname')
|
||||||
|
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.create_test_data()
|
||||||
|
self.parse_test()
|
||||||
|
self.one_cols_1output_test()
|
||||||
|
self.one_cols_multi_output_test()
|
||||||
|
self.multi_cols_output_test()
|
||||||
|
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
tdSql.close()
|
||||||
|
tdLog.success("%s successfully executed" % __file__)
|
||||||
|
|
||||||
|
|
||||||
|
tdCases.addWindows(__file__, TDTestCase())
|
||||||
|
tdCases.addLinux(__file__, TDTestCase())
|
Loading…
Reference in New Issue