未验证 提交 b1aa263c 编写于 作者: X Xiaoyu Wang 提交者: GitHub

Merge pull request #12080 from taosdata/feature/3.0_wxy

sql command 'select max(c1), c2 from t'
......@@ -113,6 +113,9 @@ typedef enum EFunctionType {
FUNCTION_TYPE_WENDTS,
FUNCTION_TYPE_WDURATION,
// internal function
FUNCTION_TYPE_SELECT_VALUE,
// user defined funcion
FUNCTION_TYPE_UDF = 10000
} EFunctionType;
......@@ -141,6 +144,7 @@ bool fmIsScalarFunc(int32_t funcId);
bool fmIsNonstandardSQLFunc(int32_t funcId);
bool fmIsStringFunc(int32_t funcId);
bool fmIsDatetimeFunc(int32_t funcId);
bool fmIsSelectFunc(int32_t funcId);
bool fmIsTimelineFunc(int32_t funcId);
bool fmIsTimeorderFunc(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_MULTI_RES_FUNC FUNC_MGT_FUNC_CLASSIFICATION_MASK(11)
#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)
......
......@@ -438,6 +438,11 @@ static int32_t translateToJson(SFunctionNode* pFunc, char* pErrBuf, int32_t len)
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
const SBuiltinFuncDefinition funcMgtBuiltins[] = {
{
......@@ -465,7 +470,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
{
.name = "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,
.dataRequiredFunc = statisDataRequired,
.getEnvFunc = getMinmaxFuncEnv,
......@@ -476,7 +481,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
{
.name = "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,
.dataRequiredFunc = statisDataRequired,
.getEnvFunc = getMinmaxFuncEnv,
......@@ -974,6 +979,16 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
.initFunc = NULL,
.sprocessFunc = toJsonFunction,
.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
......
......@@ -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 fmIsSelectFunc(int32_t funcId) { return isSpecificClassifyFunc(funcId, FUNC_MGT_SELECT_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); }
......
......@@ -256,6 +256,26 @@ static void destroyTranslateContext(STranslateContext* pCxt) {
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 isTimelineFunc(const SNode* pNode) {
return (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsTimelineFunc(((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) {
int cmp = 0;
if ('\0' != pCol->dbName[0]) {
......@@ -617,13 +637,45 @@ static EDealRes translateOperator(STranslateContext* pCxt, SOperatorNode* pOp) {
}
static EDealRes haveAggFunction(SNode* pNode, void* pContext) {
if (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsAggFunc(((SFunctionNode*)pNode)->funcId)) {
if (isAggFunc(pNode)) {
*((bool*)pContext) = true;
return DEAL_RES_END;
}
return DEAL_RES_CONTINUE;
}
static int32_t findTable(STranslateContext* pCxt, const char* pTableAlias, STableNode** pOutput) {
SArray* pTables = taosArrayGetP(pCxt->pNsLevel, pCxt->currLevel);
size_t nums = taosArrayGetSize(pTables);
for (size_t i = 0; i < nums; ++i) {
STableNode* pTable = taosArrayGetP(pTables, i);
if (NULL == pTableAlias || 0 == strcmp(pTable->tableAlias, pTableAlias)) {
*pOutput = pTable;
return TSDB_CODE_SUCCESS;
}
}
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_TABLE_NOT_EXIST, pTableAlias);
}
static bool isCountStar(SFunctionNode* pFunc) {
if (FUNCTION_TYPE_COUNT != pFunc->funcType || 1 != LIST_LENGTH(pFunc->pParameterList)) {
return false;
}
SNode* pPara = nodesListGetNode(pFunc->pParameterList, 0);
return (QUERY_NODE_COLUMN == nodeType(pPara) && 0 == strcmp(((SColumnNode*)pPara)->colName, "*"));
}
// count(*) is rewritten as count(ts) for scannning optimization
static int32_t rewriteCountStar(STranslateContext* pCxt, SFunctionNode* pCount) {
SColumnNode* pCol = nodesListGetNode(pCount->pParameterList, 0);
STableNode* pTable = NULL;
int32_t code = findTable(pCxt, ('\0' == pCol->tableAlias[0] ? NULL : pCol->tableAlias), &pTable);
if (TSDB_CODE_SUCCESS == code && QUERY_NODE_REAL_TABLE == nodeType(pTable)) {
setColumnInfoBySchema((SRealTableNode*)pTable, ((SRealTableNode*)pTable)->pMeta->schema, false, pCol);
}
return code;
}
static EDealRes translateFunction(STranslateContext* pCxt, SFunctionNode* pFunc) {
SFmGetFuncInfoParam param = {.pCtg = pCxt->pParseCxt->pCatalog,
.pRpc = pCxt->pParseCxt->pTransporter,
......@@ -631,10 +683,7 @@ static EDealRes translateFunction(STranslateContext* pCxt, SFunctionNode* pFunc)
.pErrBuf = pCxt->msgBuf.buf,
.errBufLen = pCxt->msgBuf.len};
pCxt->errCode = fmGetFuncInfo(&param, pFunc);
if (TSDB_CODE_SUCCESS != pCxt->errCode) {
return DEAL_RES_ERROR;
}
if (fmIsAggFunc(pFunc->funcId)) {
if (TSDB_CODE_SUCCESS == pCxt->errCode && fmIsAggFunc(pFunc->funcId)) {
if (beforeHaving(pCxt->currClause)) {
return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION);
}
......@@ -643,11 +692,14 @@ static EDealRes translateFunction(STranslateContext* pCxt, SFunctionNode* pFunc)
if (haveAggFunc) {
return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_AGG_FUNC_NESTING);
}
pCxt->pCurrStmt->hasAggFuncs = true;
pCxt->pCurrStmt->isTimeOrderQuery = false;
if (isCountStar(pFunc)) {
pCxt->errCode = rewriteCountStar(pCxt, pFunc);
}
}
return DEAL_RES_CONTINUE;
return TSDB_CODE_SUCCESS == pCxt->errCode ? DEAL_RES_CONTINUE : DEAL_RES_ERROR;
}
static EDealRes translateExprSubquery(STranslateContext* pCxt, SNode* pNode) {
......@@ -691,12 +743,6 @@ static int32_t translateExprList(STranslateContext* pCxt, SNodeList* pList) {
return pCxt->errCode;
}
static bool isAliasColumn(SColumnNode* pCol) { return ('\0' == pCol->tableAlias[0]); }
static bool isDistinctOrderBy(STranslateContext* pCxt) {
return (SQL_CLAUSE_ORDER_BY == pCxt->currClause && pCxt->pCurrStmt->isDistinct);
}
static SNodeList* getGroupByList(STranslateContext* pCxt) {
if (isDistinctOrderBy(pCxt)) {
return pCxt->pCurrStmt->pProjectionList;
......@@ -718,31 +764,71 @@ static int32_t getGroupByErrorCode(STranslateContext* pCxt) {
return TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION;
}
static EDealRes doCheckExprForGroupBy(SNode* pNode, void* pContext) {
STranslateContext* pCxt = (STranslateContext*)pContext;
if (!nodesIsExprNode(pNode) || (QUERY_NODE_COLUMN == nodeType(pNode) && isAliasColumn((SColumnNode*)pNode))) {
typedef struct SCheckExprForGroupByCxt {
STranslateContext* pTranslateCxt;
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;
}
if (QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsAggFunc(((SFunctionNode*)pNode)->funcId) &&
!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;
}
SNode* pGroupNode;
FOREACH(pGroupNode, getGroupByList(pCxt)) {
if (nodesEqualNode(getGroupByNode(pGroupNode), pNode)) {
FOREACH(pGroupNode, getGroupByList(pCxt->pTranslateCxt)) {
if (nodesEqualNode(getGroupByNode(pGroupNode), *pNode)) {
return DEAL_RES_IGNORE_CHILD;
}
}
if (QUERY_NODE_COLUMN == nodeType(pNode) ||
(QUERY_NODE_FUNCTION == nodeType(pNode) && fmIsAggFunc(((SFunctionNode*)pNode)->funcId) &&
isDistinctOrderBy(pCxt))) {
return generateDealNodeErrMsg(pCxt, getGroupByErrorCode(pCxt));
if (QUERY_NODE_COLUMN == nodeType(*pNode)) {
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;
}
static int32_t checkExprForGroupBy(STranslateContext* pCxt, SNode* pNode) {
nodesWalkExpr(pNode, doCheckExprForGroupBy, pCxt);
static int32_t checkExprForGroupBy(STranslateContext* pCxt, SNode** pNode) {
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;
}
......@@ -750,7 +836,29 @@ static int32_t checkExprListForGroupBy(STranslateContext* pCxt, SNodeList* pList
if (NULL == getGroupByList(pCxt)) {
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;
}
......@@ -758,11 +866,13 @@ typedef struct CheckAggColCoexistCxt {
STranslateContext* pTranslateCxt;
bool existAggFunc;
bool existCol;
int32_t selectFuncNum;
} CheckAggColCoexistCxt;
static EDealRes doCheckAggColCoexist(SNode* pNode, void* 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;
return DEAL_RES_IGNORE_CHILD;
}
......@@ -781,7 +891,9 @@ static int32_t checkAggColCoexist(STranslateContext* pCxt, SSelectStmt* pSelect)
if (!pSelect->isDistinct) {
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 TSDB_CODE_SUCCESS;
......@@ -990,19 +1102,6 @@ static SNode* createMultiResFunc(SFunctionNode* pSrcFunc, SExprNode* pExpr) {
return (SNode*)pFunc;
}
static int32_t findTable(STranslateContext* pCxt, const char* pTableAlias, STableNode** pOutput) {
SArray* pTables = taosArrayGetP(pCxt->pNsLevel, pCxt->currLevel);
size_t nums = taosArrayGetSize(pTables);
for (size_t i = 0; i < nums; ++i) {
STableNode* pTable = taosArrayGetP(pTables, i);
if (NULL == pTableAlias || 0 == strcmp(pTable->tableAlias, pTableAlias)) {
*pOutput = pTable;
return TSDB_CODE_SUCCESS;
}
}
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_TABLE_NOT_EXIST, pTableAlias);
}
static int32_t createTableAllCols(STranslateContext* pCxt, SColumnNode* pCol, SNodeList** pOutput) {
STableNode* pTable = NULL;
int32_t code = findTable(pCxt, pCol->tableAlias, &pTable);
......@@ -1228,7 +1327,7 @@ static int32_t translateHaving(STranslateContext* pCxt, SSelectStmt* pSelect) {
pCxt->currClause = SQL_CLAUSE_HAVING;
int32_t code = translateExpr(pCxt, pSelect->pHaving);
if (TSDB_CODE_SUCCESS == code) {
code = checkExprForGroupBy(pCxt, pSelect->pHaving);
code = checkExprForGroupBy(pCxt, &pSelect->pHaving);
}
return code;
}
......@@ -1511,25 +1610,6 @@ static int32_t checkLimit(STranslateContext* pCxt, SSelectStmt* pSelect) {
return TSDB_CODE_SUCCESS;
}
static bool isCountStar(SFunctionNode* pFunc) {
if (1 != LIST_LENGTH(pFunc->pParameterList)) {
return false;
}
SNode* pPara = nodesListGetNode(pFunc->pParameterList, 0);
return (QUERY_NODE_COLUMN == nodeType(pPara) && 0 == strcmp(((SColumnNode*)pPara)->colName, "*"));
}
// count(*) is rewritten as count(ts) for scannning optimization
static int32_t rewriteCountStar(STranslateContext* pCxt, SFunctionNode* pCount) {
SColumnNode* pCol = nodesListGetNode(pCount->pParameterList, 0);
STableNode* pTable = NULL;
int32_t code = findTable(pCxt, ('\0' == pCol->tableAlias[0] ? NULL : pCol->tableAlias), &pTable);
if (TSDB_CODE_SUCCESS == code && QUERY_NODE_REAL_TABLE == nodeType(pTable)) {
setColumnInfoBySchema((SRealTableNode*)pTable, ((SRealTableNode*)pTable)->pMeta->schema, false, pCol);
}
return code;
}
static int32_t createPrimaryKeyColByTable(STranslateContext* pCxt, STableNode* pTable, SNode** pPrimaryKey) {
SColumnNode* pCol = nodesMakeNode(QUERY_NODE_COLUMN);
if (NULL == pCol) {
......@@ -1553,33 +1633,22 @@ static int32_t createPrimaryKeyCol(STranslateContext* pCxt, SNode** pPrimaryKey)
return code;
}
static int32_t rewriteTimelineFunc(STranslateContext* pCxt, SFunctionNode* pFunc) {
SNode* pPrimaryKey = NULL;
int32_t code = createPrimaryKeyCol(pCxt, &pPrimaryKey);
if (TSDB_CODE_SUCCESS == code) {
code = nodesListMakeStrictAppend(&pFunc->pParameterList, pPrimaryKey);
}
return code;
}
EDealRes rewriteFuncForSelectImpl(SNode* pNode, void* pContext) {
if (QUERY_NODE_FUNCTION == nodeType(pNode)) {
STranslateContext* pCxt = pContext;
SFunctionNode* pFunc = (SFunctionNode*)pNode;
if (isCountStar(pFunc)) {
pCxt->errCode = rewriteCountStar(pCxt, pFunc);
} else if (fmIsTimelineFunc(pFunc->funcId)) {
pCxt->errCode = rewriteTimelineFunc(pCxt, pFunc);
}
if (TSDB_CODE_SUCCESS != pCxt->errCode) {
return DEAL_RES_ERROR;
static EDealRes rewriteTimelineFuncImpl(SNode* pNode, void* pContext) {
STranslateContext* pCxt = pContext;
if (isTimelineFunc(pNode)) {
SFunctionNode* pFunc = (SFunctionNode*)pNode;
SNode* pPrimaryKey = NULL;
pCxt->errCode = createPrimaryKeyCol(pCxt, &pPrimaryKey);
if (TSDB_CODE_SUCCESS == pCxt->errCode) {
pCxt->errCode = nodesListMakeStrictAppend(&pFunc->pParameterList, pPrimaryKey);
}
return TSDB_CODE_SUCCESS == pCxt->errCode ? DEAL_RES_IGNORE_CHILD : DEAL_RES_ERROR;
}
return DEAL_RES_CONTINUE;
}
static int32_t rewriteFuncForSelect(STranslateContext* pCxt, SSelectStmt* pSelect) {
nodesWalkSelectStmt(pSelect, SQL_CLAUSE_FROM, rewriteFuncForSelectImpl, pCxt);
static int32_t rewriteTimelineFunc(STranslateContext* pCxt, SSelectStmt* pSelect) {
nodesWalkSelectStmt(pSelect, SQL_CLAUSE_FROM, rewriteTimelineFuncImpl, pCxt);
return pCxt->errCode;
}
......@@ -1614,7 +1683,7 @@ static int32_t translateSelect(STranslateContext* pCxt, SSelectStmt* pSelect) {
code = checkLimit(pCxt, pSelect);
}
if (TSDB_CODE_SUCCESS == code) {
code = rewriteFuncForSelect(pCxt, pSelect);
code = rewriteTimelineFunc(pCxt, pSelect);
}
return code;
}
......
......@@ -103,7 +103,6 @@ class MockCatalogServiceImpl {
const char* tname = tNameGetTableName(pTableName);
int32_t code = copyTableSchemaMeta(db, tname, &table);
if (TSDB_CODE_SUCCESS != code) {
std::cout << "db : " << db << ", table :" << tname << std::endl;
return code;
}
*pTableMeta = table.release();
......
......@@ -67,49 +67,72 @@ TEST_F(ParserSelectTest, condition) {
TEST_F(ParserSelectTest, pseudoColumn) {
useDb("root", "test");
run("SELECT _wstartts, _wendts, COUNT(*) FROM t1 INTERVAL(10s)");
run("SELECT _WSTARTTS, _WENDTS, COUNT(*) FROM t1 INTERVAL(10s)");
}
TEST_F(ParserSelectTest, multiResFunc) {
useDb("root", "test");
run("SELECT last(*), first(*), last_row(*) FROM t1");
run("SELECT LAST(*), FIRST(*), LAST_ROW(*) FROM t1");
run("SELECT last(c1, c2), first(t1.*), last_row(c3) FROM t1");
run("SELECT LAST(c1, c2), FIRST(t1.*), LAST_ROW(c3) FROM t1");
run("SELECT last(t2.*), first(t1.c1, t2.*), last_row(t1.*, t2.*) FROM st1s1 t1, st1s2 t2 WHERE t1.ts = t2.ts");
run("SELECT LAST(t2.*), FIRST(t1.c1, t2.*), LAST_ROW(t1.*, t2.*) FROM st1s1 t1, st1s2 t2 WHERE t1.ts = t2.ts");
}
TEST_F(ParserSelectTest, timelineFunc) {
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 FIRST(ts), FIRST(c1), FIRST(c2), FIRST(c3) FROM t1");
run("SELECT last(*), first(*) FROM t1 INTERVAL(10s)");
run("SELECT LAST(*), FIRST(*) FROM t1 GROUP BY c1");
run("SELECT LAST(*), FIRST(*) FROM t1 INTERVAL(10s)");
run("SELECT diff(c1) FROM t1");
}
TEST_F(ParserSelectTest, 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 for INTERVAL clause
run("SELECT MAX(c1), MIN(c1) FROM t1 INTERVAL(10s)");
// 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");
// 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) {
useDb("root", "test");
// group by clause
// GROUP BY clause
run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0");
run("SELECT COUNT(*), c2 cnt FROM t1 WHERE c1 > 0 group by c2");
run("SELECT COUNT(*), c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c2");
run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0 group by c2 having COUNT(c1) > 10");
run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0 GROUP BY c2 having COUNT(c1) > 10");
run("SELECT COUNT(*), c1, c2 + 10, c1 + c2 cnt FROM t1 WHERE c1 > 0 group by c2, c1");
run("SELECT COUNT(*), c1, c2 + 10, c1 + c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c2, c1");
run("SELECT COUNT(*), c1 + 10, c2 cnt FROM t1 WHERE c1 > 0 group by c1 + 10, c2");
run("SELECT COUNT(*), c1 + 10, c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c1 + 10, c2");
// order by clause
run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0 group by c2 order by cnt");
run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0 GROUP BY c2 order by cnt");
run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0 group by c2 order by 1");
run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0 GROUP BY c2 order by 1");
// distinct clause
// run("SELECT distinct c1, c2 FROM t1 WHERE c1 > 0 order by c1");
......@@ -118,7 +141,7 @@ TEST_F(ParserSelectTest, clause) {
// run("SELECT distinct c1 + 10 cc1, c2 cc2 FROM t1 WHERE c1 > 0 order by cc1, c2");
// run("SELECT distinct COUNT(c2) FROM t1 WHERE c1 > 0 group by c1 order by COUNT(c2)");
// run("SELECT distinct COUNT(c2) FROM t1 WHERE c1 > 0 GROUP BY c1 order by COUNT(c2)");
}
// INTERVAL(interval_val [, interval_offset]) [SLIDING (sliding_val)] [FILL(fill_mod_and_val)]
......@@ -137,6 +160,14 @@ TEST_F(ParserSelectTest, interval) {
"INTERVAL(10s) FILL(NONE)");
}
TEST_F(ParserSelectTest, intervalSemanticCheck) {
useDb("root", "test");
run("SELECT c1 FROM t1 INTERVAL(10s)", TSDB_CODE_PAR_NOT_SINGLE_GROUP, PARSER_STAGE_TRANSLATE);
run("SELECT DISTINCT c1, c2 FROM t1 WHERE c1 > 3 INTERVAL(1d) FILL(NEXT)", TSDB_CODE_PAR_INVALID_FILL_TIME_RANGE,
PARSER_STAGE_TRANSLATE);
}
TEST_F(ParserSelectTest, semanticError) {
useDb("root", "test");
......@@ -164,7 +195,7 @@ TEST_F(ParserSelectTest, semanticError) {
run("SELECT c2 FROM t1 WHERE COUNT(*) > 0", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION, PARSER_STAGE_TRANSLATE);
run("SELECT c2 FROM t1 group by COUNT(*)", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION, PARSER_STAGE_TRANSLATE);
run("SELECT c2 FROM t1 GROUP BY COUNT(*)", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION, PARSER_STAGE_TRANSLATE);
// TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT
run("SELECT c2 FROM t1 order by 0", TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT, PARSER_STAGE_TRANSLATE);
......@@ -174,13 +205,13 @@ TEST_F(ParserSelectTest, semanticError) {
// TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION
run("SELECT COUNT(*) cnt FROM t1 having c1 > 0", TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION, PARSER_STAGE_TRANSLATE);
run("SELECT COUNT(*) cnt FROM t1 group by c2 having c1 > 0", TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION,
run("SELECT COUNT(*) cnt FROM t1 GROUP BY c2 having c1 > 0", TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION,
PARSER_STAGE_TRANSLATE);
run("SELECT COUNT(*), c1 cnt FROM t1 group by c2 having c2 > 0", TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION,
run("SELECT COUNT(*), c1 cnt FROM t1 GROUP BY c2 having c2 > 0", TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION,
PARSER_STAGE_TRANSLATE);
run("SELECT COUNT(*) cnt FROM t1 group by c2 having c2 > 0 order by c1", TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION,
run("SELECT COUNT(*) cnt FROM t1 GROUP BY c2 having c2 > 0 order by c1", TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION,
PARSER_STAGE_TRANSLATE);
// TSDB_CODE_PAR_NOT_SINGLE_GROUP
......
......@@ -23,30 +23,45 @@ class PlanGroupByTest : public PlannerTestBase {};
TEST_F(PlanGroupByTest, basic) {
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) {
useDb("root", "test");
// order by aggfunc
run("select count(*), sum(c1) from t1 order by sum(c1)");
// order by alias of aggfunc
// run("select count(*), sum(c1) a from t1 order by a");
// ORDER BY aggfunc
run("SELECT COUNT(*), SUM(c1) FROM t1 ORDER BY SUM(c1)");
// ORDER BY alias of aggfunc
// run("SELECT COUNT(*), SUM(c1) a FROM t1 ORDER BY a");
}
TEST_F(PlanGroupByTest, aggFunc) {
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' "
"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)");
}
\ No newline at end of file
......@@ -25,3 +25,12 @@ TEST_F(PlanSessionTest, basic) {
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)");
}
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)");
}
......@@ -101,7 +101,7 @@ class TDTestCase:
# tdSql.error("select distinct c1, ts from stb1 group by c2")
tdSql.error("select distinct c1, ts from t1 group by c2")
# tdSql.error("select distinct c1, max(c2) from stb1 ")
tdSql.error("select distinct c1, max(c2) from t1 ")
# tdSql.error("select distinct c1, max(c2) from t1 ")
# tdSql.error("select max(c2), distinct c1 from stb1 ")
tdSql.error("select max(c2), distinct c1 from t1 ")
# tdSql.error("select distinct c1, c2 from stb1 where c1 > 3 group by t0")
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册