feat: sql commadn 'select max(c1), c2 from t2'
This commit is contained in:
parent
f99c01e66e
commit
3b4f9b91cf
|
@ -113,6 +113,9 @@ typedef enum EFunctionType {
|
||||||
FUNCTION_TYPE_WENDTS,
|
FUNCTION_TYPE_WENDTS,
|
||||||
FUNCTION_TYPE_WDURATION,
|
FUNCTION_TYPE_WDURATION,
|
||||||
|
|
||||||
|
// internal function
|
||||||
|
FUNCTION_TYPE_SELECT_VALUE,
|
||||||
|
|
||||||
// user defined funcion
|
// user defined funcion
|
||||||
FUNCTION_TYPE_UDF = 10000
|
FUNCTION_TYPE_UDF = 10000
|
||||||
} EFunctionType;
|
} EFunctionType;
|
||||||
|
@ -141,6 +144,7 @@ bool fmIsScalarFunc(int32_t funcId);
|
||||||
bool fmIsNonstandardSQLFunc(int32_t funcId);
|
bool fmIsNonstandardSQLFunc(int32_t funcId);
|
||||||
bool fmIsStringFunc(int32_t funcId);
|
bool fmIsStringFunc(int32_t funcId);
|
||||||
bool fmIsDatetimeFunc(int32_t funcId);
|
bool fmIsDatetimeFunc(int32_t funcId);
|
||||||
|
bool fmIsSelectFunc(int32_t funcId);
|
||||||
bool fmIsTimelineFunc(int32_t funcId);
|
bool fmIsTimelineFunc(int32_t funcId);
|
||||||
bool fmIsTimeorderFunc(int32_t funcId);
|
bool fmIsTimeorderFunc(int32_t funcId);
|
||||||
bool fmIsPseudoColumnFunc(int32_t funcId);
|
bool fmIsPseudoColumnFunc(int32_t funcId);
|
||||||
|
|
|
@ -39,6 +39,7 @@ extern "C" {
|
||||||
#define FUNC_MGT_DYNAMIC_SCAN_OPTIMIZED FUNC_MGT_FUNC_CLASSIFICATION_MASK(10)
|
#define FUNC_MGT_DYNAMIC_SCAN_OPTIMIZED FUNC_MGT_FUNC_CLASSIFICATION_MASK(10)
|
||||||
#define FUNC_MGT_MULTI_RES_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(11)
|
#define FUNC_MGT_MULTI_RES_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(11)
|
||||||
#define FUNC_MGT_SCAN_PC_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(12)
|
#define FUNC_MGT_SCAN_PC_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(12)
|
||||||
|
#define FUNC_MGT_SELECT_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(13)
|
||||||
|
|
||||||
#define FUNC_MGT_TEST_MASK(val, mask) (((val) & (mask)) != 0)
|
#define FUNC_MGT_TEST_MASK(val, mask) (((val) & (mask)) != 0)
|
||||||
|
|
||||||
|
|
|
@ -438,6 +438,11 @@ static int32_t translateToJson(SFunctionNode* pFunc, char* pErrBuf, int32_t len)
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t translateSelectValue(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
|
||||||
|
pFunc->node.resType = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 0))->resType;
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
||||||
{
|
{
|
||||||
|
@ -465,7 +470,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
||||||
{
|
{
|
||||||
.name = "min",
|
.name = "min",
|
||||||
.type = FUNCTION_TYPE_MIN,
|
.type = FUNCTION_TYPE_MIN,
|
||||||
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SPECIAL_DATA_REQUIRED,
|
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SPECIAL_DATA_REQUIRED | FUNC_MGT_SELECT_FUNC,
|
||||||
.translateFunc = translateInOutNum,
|
.translateFunc = translateInOutNum,
|
||||||
.dataRequiredFunc = statisDataRequired,
|
.dataRequiredFunc = statisDataRequired,
|
||||||
.getEnvFunc = getMinmaxFuncEnv,
|
.getEnvFunc = getMinmaxFuncEnv,
|
||||||
|
@ -476,7 +481,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
||||||
{
|
{
|
||||||
.name = "max",
|
.name = "max",
|
||||||
.type = FUNCTION_TYPE_MAX,
|
.type = FUNCTION_TYPE_MAX,
|
||||||
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SPECIAL_DATA_REQUIRED,
|
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SPECIAL_DATA_REQUIRED | FUNC_MGT_SELECT_FUNC,
|
||||||
.translateFunc = translateInOutNum,
|
.translateFunc = translateInOutNum,
|
||||||
.dataRequiredFunc = statisDataRequired,
|
.dataRequiredFunc = statisDataRequired,
|
||||||
.getEnvFunc = getMinmaxFuncEnv,
|
.getEnvFunc = getMinmaxFuncEnv,
|
||||||
|
@ -974,6 +979,16 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
||||||
.initFunc = NULL,
|
.initFunc = NULL,
|
||||||
.sprocessFunc = toJsonFunction,
|
.sprocessFunc = toJsonFunction,
|
||||||
.finalizeFunc = NULL
|
.finalizeFunc = NULL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "_select_value",
|
||||||
|
.type = FUNCTION_TYPE_SELECT_VALUE,
|
||||||
|
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_SELECT_FUNC,
|
||||||
|
.translateFunc = translateSelectValue,
|
||||||
|
.getEnvFunc = NULL,
|
||||||
|
.initFunc = NULL,
|
||||||
|
.sprocessFunc = NULL,
|
||||||
|
.finalizeFunc = NULL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
|
@ -145,6 +145,8 @@ bool fmIsAggFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MG
|
||||||
|
|
||||||
bool fmIsScalarFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MGT_SCALAR_FUNC); }
|
bool fmIsScalarFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MGT_SCALAR_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); }
|
||||||
|
|
||||||
bool fmIsPseudoColumnFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MGT_PSEUDO_COLUMN_FUNC); }
|
bool fmIsPseudoColumnFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MGT_PSEUDO_COLUMN_FUNC); }
|
||||||
|
|
|
@ -256,6 +256,22 @@ static void destroyTranslateContext(STranslateContext* pCxt) {
|
||||||
taosHashCleanup(pCxt->pTables);
|
taosHashCleanup(pCxt->pTables);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isAliasColumn(const SNode* pNode) {
|
||||||
|
return (QUERY_NODE_COLUMN == nodeType(pNode) && ('\0' == ((SColumnNode*)pNode)->tableAlias[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isAggFunc(const SNode* pNode) {
|
||||||
|
return (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsAggFunc(((SFunctionNode*)pNode)->funcId));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isSelectFunc(const SNode* pNode) {
|
||||||
|
return (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsSelectFunc(((SFunctionNode*)pNode)->funcId));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isDistinctOrderBy(STranslateContext* pCxt) {
|
||||||
|
return (SQL_CLAUSE_ORDER_BY == pCxt->currClause && pCxt->pCurrStmt->isDistinct);
|
||||||
|
}
|
||||||
|
|
||||||
static bool belongTable(const char* currentDb, const SColumnNode* pCol, const STableNode* pTable) {
|
static bool belongTable(const char* currentDb, const SColumnNode* pCol, const STableNode* pTable) {
|
||||||
int cmp = 0;
|
int cmp = 0;
|
||||||
if ('\0' != pCol->dbName[0]) {
|
if ('\0' != pCol->dbName[0]) {
|
||||||
|
@ -617,7 +633,7 @@ static EDealRes translateOperator(STranslateContext* pCxt, SOperatorNode* pOp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static EDealRes haveAggFunction(SNode* pNode, void* pContext) {
|
static EDealRes haveAggFunction(SNode* pNode, void* pContext) {
|
||||||
if (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsAggFunc(((SFunctionNode*)pNode)->funcId)) {
|
if (isAggFunc(pNode)) {
|
||||||
*((bool*)pContext) = true;
|
*((bool*)pContext) = true;
|
||||||
return DEAL_RES_END;
|
return DEAL_RES_END;
|
||||||
}
|
}
|
||||||
|
@ -758,18 +774,6 @@ static int32_t translateExprList(STranslateContext* pCxt, SNodeList* pList) {
|
||||||
return pCxt->errCode;
|
return pCxt->errCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isAliasColumn(const SNode* pNode) {
|
|
||||||
return (QUERY_NODE_COLUMN == nodeType(pNode) && ('\0' == ((SColumnNode*)pNode)->tableAlias[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isAggFunc(const SNode* pNode) {
|
|
||||||
return (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsAggFunc(((SFunctionNode*)pNode)->funcId));
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isDistinctOrderBy(STranslateContext* pCxt) {
|
|
||||||
return (SQL_CLAUSE_ORDER_BY == pCxt->currClause && pCxt->pCurrStmt->isDistinct);
|
|
||||||
}
|
|
||||||
|
|
||||||
static SNodeList* getGroupByList(STranslateContext* pCxt) {
|
static SNodeList* getGroupByList(STranslateContext* pCxt) {
|
||||||
if (isDistinctOrderBy(pCxt)) {
|
if (isDistinctOrderBy(pCxt)) {
|
||||||
return pCxt->pCurrStmt->pProjectionList;
|
return pCxt->pCurrStmt->pProjectionList;
|
||||||
|
@ -791,28 +795,71 @@ static int32_t getGroupByErrorCode(STranslateContext* pCxt) {
|
||||||
return TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION;
|
return TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
static EDealRes doCheckExprForGroupBy(SNode* pNode, void* pContext) {
|
typedef struct SCheckExprForGroupByCxt {
|
||||||
STranslateContext* pCxt = (STranslateContext*)pContext;
|
STranslateContext* pTranslateCxt;
|
||||||
if (!nodesIsExprNode(pNode) || isAliasColumn(pNode)) {
|
int32_t selectFuncNum;
|
||||||
|
bool hasSelectValFunc;
|
||||||
|
} SCheckExprForGroupByCxt;
|
||||||
|
|
||||||
|
static EDealRes rewriteColToSelectValFunc(STranslateContext* pCxt, bool* pHasSelectValFunc, SNode** pNode) {
|
||||||
|
SFunctionNode* pFunc = nodesMakeNode(QUERY_NODE_FUNCTION);
|
||||||
|
if (NULL == pFunc) {
|
||||||
|
pCxt->errCode = TSDB_CODE_OUT_OF_MEMORY;
|
||||||
|
return DEAL_RES_ERROR;
|
||||||
|
}
|
||||||
|
strcpy(pFunc->functionName, "_select_value");
|
||||||
|
pCxt->errCode = nodesListMakeAppend(&pFunc->pParameterList, *pNode);
|
||||||
|
if (TSDB_CODE_SUCCESS == pCxt->errCode) {
|
||||||
|
translateFunction(pCxt, pFunc);
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == pCxt->errCode) {
|
||||||
|
*pNode = (SNode*)pFunc;
|
||||||
|
if (NULL != pHasSelectValFunc) {
|
||||||
|
*pHasSelectValFunc = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nodesDestroyNode(pFunc);
|
||||||
|
}
|
||||||
|
return TSDB_CODE_SUCCESS == pCxt->errCode ? DEAL_RES_IGNORE_CHILD : DEAL_RES_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EDealRes doCheckExprForGroupBy(SNode** pNode, void* pContext) {
|
||||||
|
SCheckExprForGroupByCxt* pCxt = (SCheckExprForGroupByCxt*)pContext;
|
||||||
|
if (!nodesIsExprNode(*pNode) || isAliasColumn(*pNode)) {
|
||||||
return DEAL_RES_CONTINUE;
|
return DEAL_RES_CONTINUE;
|
||||||
}
|
}
|
||||||
if (isAggFunc(pNode) && !isDistinctOrderBy(pCxt)) {
|
pCxt->selectFuncNum += isSelectFunc(*pNode) ? 1 : 0;
|
||||||
|
if (pCxt->selectFuncNum > 1 && pCxt->hasSelectValFunc) {
|
||||||
|
return generateDealNodeErrMsg(pCxt->pTranslateCxt, getGroupByErrorCode(pCxt->pTranslateCxt));
|
||||||
|
}
|
||||||
|
if (isAggFunc(*pNode) && !isDistinctOrderBy(pCxt->pTranslateCxt)) {
|
||||||
return DEAL_RES_IGNORE_CHILD;
|
return DEAL_RES_IGNORE_CHILD;
|
||||||
}
|
}
|
||||||
SNode* pGroupNode;
|
SNode* pGroupNode;
|
||||||
FOREACH(pGroupNode, getGroupByList(pCxt)) {
|
FOREACH(pGroupNode, getGroupByList(pCxt->pTranslateCxt)) {
|
||||||
if (nodesEqualNode(getGroupByNode(pGroupNode), pNode)) {
|
if (nodesEqualNode(getGroupByNode(pGroupNode), *pNode)) {
|
||||||
return DEAL_RES_IGNORE_CHILD;
|
return DEAL_RES_IGNORE_CHILD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (QUERY_NODE_COLUMN == nodeType(pNode) || (isAggFunc(pNode) && isDistinctOrderBy(pCxt))) {
|
if (QUERY_NODE_COLUMN == nodeType(*pNode)) {
|
||||||
return generateDealNodeErrMsg(pCxt, getGroupByErrorCode(pCxt));
|
if (pCxt->selectFuncNum > 1) {
|
||||||
|
return generateDealNodeErrMsg(pCxt->pTranslateCxt, getGroupByErrorCode(pCxt->pTranslateCxt));
|
||||||
|
} else {
|
||||||
|
return rewriteColToSelectValFunc(pCxt->pTranslateCxt, &pCxt->hasSelectValFunc, pNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isAggFunc(*pNode) && isDistinctOrderBy(pCxt->pTranslateCxt)) {
|
||||||
|
return generateDealNodeErrMsg(pCxt->pTranslateCxt, getGroupByErrorCode(pCxt->pTranslateCxt));
|
||||||
}
|
}
|
||||||
return DEAL_RES_CONTINUE;
|
return DEAL_RES_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t checkExprForGroupBy(STranslateContext* pCxt, SNode* pNode) {
|
static int32_t checkExprForGroupBy(STranslateContext* pCxt, SNode** pNode) {
|
||||||
nodesWalkExpr(pNode, doCheckExprForGroupBy, pCxt);
|
SCheckExprForGroupByCxt cxt = {.pTranslateCxt = pCxt, .selectFuncNum = 0, .hasSelectValFunc = false};
|
||||||
|
nodesRewriteExpr(pNode, doCheckExprForGroupBy, &cxt);
|
||||||
|
if (cxt.selectFuncNum != 1 && cxt.hasSelectValFunc) {
|
||||||
|
return generateSyntaxErrMsg(&pCxt->msgBuf, getGroupByErrorCode(pCxt));
|
||||||
|
}
|
||||||
return pCxt->errCode;
|
return pCxt->errCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -820,7 +867,29 @@ static int32_t checkExprListForGroupBy(STranslateContext* pCxt, SNodeList* pList
|
||||||
if (NULL == getGroupByList(pCxt)) {
|
if (NULL == getGroupByList(pCxt)) {
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
nodesWalkExprs(pList, doCheckExprForGroupBy, pCxt);
|
SCheckExprForGroupByCxt cxt = {.pTranslateCxt = pCxt, .selectFuncNum = 0, .hasSelectValFunc = false};
|
||||||
|
nodesRewriteExprs(pList, doCheckExprForGroupBy, &cxt);
|
||||||
|
if (cxt.selectFuncNum != 1 && cxt.hasSelectValFunc) {
|
||||||
|
return generateSyntaxErrMsg(&pCxt->msgBuf, getGroupByErrorCode(pCxt));
|
||||||
|
}
|
||||||
|
return pCxt->errCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EDealRes rewriteColsToSelectValFuncImpl(SNode** pNode, void* pContext) {
|
||||||
|
if (isAggFunc(*pNode)) {
|
||||||
|
return DEAL_RES_IGNORE_CHILD;
|
||||||
|
}
|
||||||
|
if (QUERY_NODE_COLUMN == nodeType(*pNode)) {
|
||||||
|
return rewriteColToSelectValFunc((STranslateContext*)pContext, NULL, pNode);
|
||||||
|
}
|
||||||
|
return DEAL_RES_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t rewriteColsToSelectValFunc(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
|
nodesRewriteExprs(pSelect->pProjectionList, rewriteColsToSelectValFuncImpl, pCxt);
|
||||||
|
if (TSDB_CODE_SUCCESS == pCxt->errCode && !pSelect->isDistinct) {
|
||||||
|
nodesRewriteExprs(pSelect->pOrderByList, rewriteColsToSelectValFuncImpl, pCxt);
|
||||||
|
}
|
||||||
return pCxt->errCode;
|
return pCxt->errCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -828,11 +897,13 @@ typedef struct CheckAggColCoexistCxt {
|
||||||
STranslateContext* pTranslateCxt;
|
STranslateContext* pTranslateCxt;
|
||||||
bool existAggFunc;
|
bool existAggFunc;
|
||||||
bool existCol;
|
bool existCol;
|
||||||
|
int32_t selectFuncNum;
|
||||||
} CheckAggColCoexistCxt;
|
} CheckAggColCoexistCxt;
|
||||||
|
|
||||||
static EDealRes doCheckAggColCoexist(SNode* pNode, void* pContext) {
|
static EDealRes doCheckAggColCoexist(SNode* pNode, void* pContext) {
|
||||||
CheckAggColCoexistCxt* pCxt = (CheckAggColCoexistCxt*)pContext;
|
CheckAggColCoexistCxt* pCxt = (CheckAggColCoexistCxt*)pContext;
|
||||||
if (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsAggFunc(((SFunctionNode*)pNode)->funcId)) {
|
pCxt->selectFuncNum += isSelectFunc(pNode) ? 1 : 0;
|
||||||
|
if (isAggFunc(pNode)) {
|
||||||
pCxt->existAggFunc = true;
|
pCxt->existAggFunc = true;
|
||||||
return DEAL_RES_IGNORE_CHILD;
|
return DEAL_RES_IGNORE_CHILD;
|
||||||
}
|
}
|
||||||
|
@ -851,7 +922,9 @@ static int32_t checkAggColCoexist(STranslateContext* pCxt, SSelectStmt* pSelect)
|
||||||
if (!pSelect->isDistinct) {
|
if (!pSelect->isDistinct) {
|
||||||
nodesWalkExprs(pSelect->pOrderByList, doCheckAggColCoexist, &cxt);
|
nodesWalkExprs(pSelect->pOrderByList, doCheckAggColCoexist, &cxt);
|
||||||
}
|
}
|
||||||
if ((cxt.existAggFunc || NULL != pSelect->pWindow) && cxt.existCol) {
|
if (1 == cxt.selectFuncNum) {
|
||||||
|
return rewriteColsToSelectValFunc(pCxt, pSelect);
|
||||||
|
} else if ((cxt.selectFuncNum > 1 || cxt.existAggFunc || NULL != pSelect->pWindow) && cxt.existCol) {
|
||||||
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_SINGLE_GROUP);
|
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_SINGLE_GROUP);
|
||||||
}
|
}
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
|
@ -1285,7 +1358,7 @@ static int32_t translateHaving(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
pCxt->currClause = SQL_CLAUSE_HAVING;
|
pCxt->currClause = SQL_CLAUSE_HAVING;
|
||||||
int32_t code = translateExpr(pCxt, pSelect->pHaving);
|
int32_t code = translateExpr(pCxt, pSelect->pHaving);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = checkExprForGroupBy(pCxt, pSelect->pHaving);
|
code = checkExprForGroupBy(pCxt, &pSelect->pHaving);
|
||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,6 @@ class MockCatalogServiceImpl {
|
||||||
const char* tname = tNameGetTableName(pTableName);
|
const char* tname = tNameGetTableName(pTableName);
|
||||||
int32_t code = copyTableSchemaMeta(db, tname, &table);
|
int32_t code = copyTableSchemaMeta(db, tname, &table);
|
||||||
if (TSDB_CODE_SUCCESS != code) {
|
if (TSDB_CODE_SUCCESS != code) {
|
||||||
std::cout << "db : " << db << ", table :" << tname << std::endl;
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
*pTableMeta = table.release();
|
*pTableMeta = table.release();
|
||||||
|
|
|
@ -94,6 +94,7 @@ TEST_F(ParserSelectTest, timelineFunc) {
|
||||||
|
|
||||||
TEST_F(ParserSelectTest, selectFunc) {
|
TEST_F(ParserSelectTest, selectFunc) {
|
||||||
useDb("root", "test");
|
useDb("root", "test");
|
||||||
|
|
||||||
// select function
|
// select function
|
||||||
run("SELECT MAX(c1), MIN(c1) FROM t1");
|
run("SELECT MAX(c1), MIN(c1) FROM t1");
|
||||||
// select function for GROUP BY clause
|
// select function for GROUP BY clause
|
||||||
|
@ -102,8 +103,14 @@ TEST_F(ParserSelectTest, selectFunc) {
|
||||||
run("SELECT MAX(c1), MIN(c1) FROM t1 INTERVAL(10s)");
|
run("SELECT MAX(c1), MIN(c1) FROM t1 INTERVAL(10s)");
|
||||||
// select function along with the columns of select row
|
// select function along with the columns of select row
|
||||||
run("SELECT MAX(c1), c2 FROM t1");
|
run("SELECT MAX(c1), c2 FROM t1");
|
||||||
run("SELECT MAX(c1), * FROM t1");
|
|
||||||
run("SELECT MAX(c1), t1.* FROM t1");
|
run("SELECT MAX(c1), t1.* FROM t1");
|
||||||
|
// select function along with the columns of select row, and with GROUP BY clause
|
||||||
|
run("SELECT MAX(c1), c2 FROM t1 GROUP BY c3");
|
||||||
|
run("SELECT MAX(c1), t1.* FROM t1 GROUP BY c3");
|
||||||
|
// select function along with the columns of select row, and with window clause
|
||||||
|
run("SELECT MAX(c1), c2 FROM t1 INTERVAL(10s)");
|
||||||
|
run("SELECT MAX(c1), c2 FROM t1 SESSION(ts, 10s)");
|
||||||
|
run("SELECT MAX(c1), c2 FROM t1 STATE_WINDOW(c3)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserSelectTest, clause) {
|
TEST_F(ParserSelectTest, clause) {
|
||||||
|
@ -154,7 +161,7 @@ TEST_F(ParserSelectTest, interval) {
|
||||||
TEST_F(ParserSelectTest, intervalSemanticCheck) {
|
TEST_F(ParserSelectTest, intervalSemanticCheck) {
|
||||||
useDb("root", "test");
|
useDb("root", "test");
|
||||||
|
|
||||||
run("SELECT c1 FROM t1 INTERVAL(10s)");
|
run("SELECT c1 FROM t1 INTERVAL(10s)", TSDB_CODE_PAR_NOT_SINGLE_GROUP, PARSER_STAGE_TRANSLATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserSelectTest, semanticError) {
|
TEST_F(ParserSelectTest, semanticError) {
|
||||||
|
|
|
@ -23,30 +23,45 @@ class PlanGroupByTest : public PlannerTestBase {};
|
||||||
TEST_F(PlanGroupByTest, basic) {
|
TEST_F(PlanGroupByTest, basic) {
|
||||||
useDb("root", "test");
|
useDb("root", "test");
|
||||||
|
|
||||||
run("select count(*) from t1");
|
run("SELECT COUNT(*) FROM t1");
|
||||||
|
|
||||||
run("select c1, max(c3), min(c3), count(*) from t1 group by c1");
|
run("SELECT c1, MAX(c3), MIN(c3), COUNT(*) FROM t1 GROUP BY c1");
|
||||||
|
|
||||||
run("select c1 + c3, c1 + count(*) from t1 where c2 = 'abc' group by c1, c3");
|
run("SELECT c1 + c3, c1 + COUNT(*) FROM t1 WHERE c2 = 'abc' GROUP BY c1, c3");
|
||||||
|
|
||||||
run("select c1 + c3, sum(c4 * c5) from t1 where concat(c2, 'wwww') = 'abcwww' group by c1 + c3");
|
run("SELECT c1 + c3, SUM(c4 * c5) FROM t1 WHERE CONCAT(c2, 'wwww') = 'abcwww' GROUP BY c1 + c3");
|
||||||
|
|
||||||
run("select sum(ceil(c1)) from t1 group by ceil(c1)");
|
run("SELECT SUM(CEIL(c1)) FROM t1 GROUP BY CEIL(c1)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PlanGroupByTest, withOrderBy) {
|
TEST_F(PlanGroupByTest, withOrderBy) {
|
||||||
useDb("root", "test");
|
useDb("root", "test");
|
||||||
|
|
||||||
// order by aggfunc
|
// ORDER BY aggfunc
|
||||||
run("select count(*), sum(c1) from t1 order by sum(c1)");
|
run("SELECT COUNT(*), SUM(c1) FROM t1 ORDER BY SUM(c1)");
|
||||||
// order by alias of aggfunc
|
// ORDER BY alias of aggfunc
|
||||||
// run("select count(*), sum(c1) a from t1 order by a");
|
// run("SELECT COUNT(*), SUM(c1) a FROM t1 ORDER BY a");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PlanGroupByTest, aggFunc) {
|
TEST_F(PlanGroupByTest, aggFunc) {
|
||||||
useDb("root", "test");
|
useDb("root", "test");
|
||||||
|
|
||||||
run("select last(*), first(*) from t1");
|
run("SELECT LAST(*), FIRST(*) FROM t1");
|
||||||
|
|
||||||
run("select last(*), first(*) from t1 group by c1");
|
run("SELECT LAST(*), FIRST(*) FROM t1 GROUP BY c1");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PlanGroupByTest, selectFunc) {
|
||||||
|
useDb("root", "test");
|
||||||
|
|
||||||
|
// select function
|
||||||
|
run("SELECT MAX(c1), MIN(c1) FROM t1");
|
||||||
|
// select function for GROUP BY clause
|
||||||
|
run("SELECT MAX(c1), MIN(c1) FROM t1 GROUP BY c1");
|
||||||
|
// select function along with the columns of select row
|
||||||
|
run("SELECT MAX(c1), c2 FROM t1");
|
||||||
|
run("SELECT MAX(c1), t1.* FROM t1");
|
||||||
|
// select function along with the columns of select row, and with GROUP BY clause
|
||||||
|
run("SELECT MAX(c1), c2 FROM t1 GROUP BY c3");
|
||||||
|
run("SELECT MAX(c1), t1.* FROM t1 GROUP BY c3");
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,3 +42,12 @@ TEST_F(PlanIntervalTest, fill) {
|
||||||
"WHERE ts > TIMESTAMP '2022-04-01 00:00:00' and ts < TIMESTAMP '2022-04-30 23:59:59' "
|
"WHERE ts > TIMESTAMP '2022-04-01 00:00:00' and ts < TIMESTAMP '2022-04-30 23:59:59' "
|
||||||
"INTERVAL(10s) FILL(VALUE, 10, 20)");
|
"INTERVAL(10s) FILL(VALUE, 10, 20)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(PlanIntervalTest, selectFunc) {
|
||||||
|
useDb("root", "test");
|
||||||
|
|
||||||
|
// select function for INTERVAL clause
|
||||||
|
run("SELECT MAX(c1), MIN(c1) FROM t1 INTERVAL(10s)");
|
||||||
|
// select function along with the columns of select row, and with INTERVAL clause
|
||||||
|
run("SELECT MAX(c1), c2 FROM t1 INTERVAL(10s)");
|
||||||
|
}
|
|
@ -25,3 +25,12 @@ TEST_F(PlanSessionTest, basic) {
|
||||||
|
|
||||||
run("select count(*) from t1 session(ts, 10s)");
|
run("select count(*) from t1 session(ts, 10s)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(PlanSessionTest, selectFunc) {
|
||||||
|
useDb("root", "test");
|
||||||
|
|
||||||
|
// select function for SESSION clause
|
||||||
|
run("SELECT MAX(c1), MIN(c1) FROM t1 SESSION(ts, 10s)");
|
||||||
|
// select function along with the columns of select row, and with SESSION clause
|
||||||
|
run("SELECT MAX(c1), c2 FROM t1 SESSION(ts, 10s)");
|
||||||
|
}
|
||||||
|
|
|
@ -31,3 +31,12 @@ TEST_F(PlanStateTest, stateExpr) {
|
||||||
|
|
||||||
run("select count(*) from t1 state_window(c1 + 10)");
|
run("select count(*) from t1 state_window(c1 + 10)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(PlanStateTest, selectFunc) {
|
||||||
|
useDb("root", "test");
|
||||||
|
|
||||||
|
// select function for STATE_WINDOW clause
|
||||||
|
run("SELECT MAX(c1), MIN(c1) FROM t1 STATE_WINDOW(c3)");
|
||||||
|
// select function along with the columns of select row, and with STATE_WINDOW clause
|
||||||
|
run("SELECT MAX(c1), c2 FROM t1 STATE_WINDOW(c3)");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue