diff --git a/include/common/common.h b/include/common/common.h index d99e4a78b7..1c3a0e22f7 100644 --- a/include/common/common.h +++ b/include/common/common.h @@ -55,11 +55,18 @@ typedef struct SDataBlockInfo { int64_t uid; } SDataBlockInfo; +typedef struct SConstantItem { + SColumnInfo info; + int32_t startIndex; // run-length-encoding to save the space for multiple rows + int32_t endIndex; + SVariant value; +} SConstantItem; + typedef struct SSDataBlock { SColumnDataAgg *pBlockAgg; - SArray *pDataBlock; // SArray - SArray *pTagsList; // SArray for tag value - SDataBlockInfo info; + SArray *pDataBlock; // SArray + SArray *pConstantList; // SArray, it is a constant/tags value of the corresponding result value. + SDataBlockInfo info; } SSDataBlock; typedef struct SColumnInfoData { @@ -83,7 +90,7 @@ typedef struct SLimit { typedef struct SOrder { uint32_t order; - int32_t orderColId; + SColumn col; } SOrder; typedef struct SGroupbyExpr { diff --git a/include/common/taosmsg.h b/include/common/taosmsg.h index 4718d0e4b3..a4bf388309 100644 --- a/include/common/taosmsg.h +++ b/include/common/taosmsg.h @@ -277,7 +277,7 @@ typedef struct SSchema { uint8_t type; char name[TSDB_COL_NAME_LEN]; int16_t colId; - int16_t bytes; + int32_t bytes; } SSchema; //#endif diff --git a/include/common/tglobal.h b/include/common/tglobal.h index f3fce8becd..4296160c8b 100644 --- a/include/common/tglobal.h +++ b/include/common/tglobal.h @@ -58,6 +58,7 @@ extern int32_t tsCompressColData; extern int32_t tsMaxNumOfDistinctResults; extern char tsTempDir[]; extern int64_t tsMaxVnodeQueuedBytes; +extern int tsCompatibleModel; // 2.0 compatible model //query buffer management extern int32_t tsQueryBufferSize; // maximum allowed usage buffer size in MB for each data node during query processing diff --git a/include/libs/function/function.h b/include/libs/function/function.h index 92d8c972f5..d7360a81bc 100644 --- a/include/libs/function/function.h +++ b/include/libs/function/function.h @@ -229,7 +229,7 @@ typedef struct SScalarFunctionInfo { typedef struct SMultiFunctionsDesc { bool stableQuery; bool groupbyColumn; - bool simpleAgg; + bool agg; bool arithmeticOnAgg; bool projectionQuery; bool hasFilter; @@ -261,6 +261,7 @@ int32_t qIsBuiltinFunction(const char* name, int32_t len, bool* scalarFunction); bool qIsValidUdf(SArray* pUdfInfo, const char* name, int32_t len, int32_t* functionId); bool qIsAggregateFunction(const char* functionName); +bool qIsSelectivityFunction(const char* functionName); tExprNode* exprTreeFromBinary(const void* data, size_t size); diff --git a/include/libs/parser/parser.h b/include/libs/parser/parser.h index 2dec203ce8..0e6c352d71 100644 --- a/include/libs/parser/parser.h +++ b/include/libs/parser/parser.h @@ -86,7 +86,7 @@ typedef struct SQueryStmtInfo { SLimit slimit; STagCond tagCond; SArray * colCond; - SOrder order; + SArray * order; int16_t numOfTables; int16_t curTableIdx; STableMetaInfo **pTableMetaInfo; diff --git a/source/common/src/tglobal.c b/source/common/src/tglobal.c index 4f30327c06..b4d74dd298 100644 --- a/source/common/src/tglobal.c +++ b/source/common/src/tglobal.c @@ -79,6 +79,11 @@ int32_t tsCompressMsgSize = -1; */ int32_t tsCompressColData = -1; +/* + * denote if 3.0 query pattern compatible for 2.0 + */ +int32_t tsCompatibleModel = 1; + // client int32_t tsMaxSQLStringLen = TSDB_MAX_ALLOWED_SQL_LEN; int32_t tsMaxWildCardsLen = TSDB_PATTERN_STRING_DEFAULT_LEN; diff --git a/source/libs/function/src/taggfunction.c b/source/libs/function/src/taggfunction.c index dc6eadf7d8..00f59e8b87 100644 --- a/source/libs/function/src/taggfunction.c +++ b/source/libs/function/src/taggfunction.c @@ -4589,7 +4589,7 @@ SAggFunctionInfo aggFunc[35] = {{ }, { // 16 - "ts", + "dummy", FUNCTION_TYPE_AGG, FUNCTION_TS, FUNCTION_TS, diff --git a/source/libs/function/src/tfunction.c b/source/libs/function/src/tfunction.c index 7e3b4bcd5d..9e70b9a68d 100644 --- a/source/libs/function/src/tfunction.c +++ b/source/libs/function/src/tfunction.c @@ -54,6 +54,18 @@ bool qIsAggregateFunction(const char* functionName) { return !scalarfunc; } +bool qIsSelectivityFunction(const char* functionName) { + assert(functionName != NULL); + pthread_once(&functionHashTableInit, doInitFunctionHashTable); + + size_t len = strlen(functionName); + SAggFunctionInfo** pInfo = taosHashGet(functionHashTable, functionName, len); + if (pInfo != NULL) { + return ((*pInfo)->status | FUNCSTATE_SELECTIVITY) != 0; + } + + return false; +} SAggFunctionInfo* qGetFunctionInfo(const char* name, int32_t len) { pthread_once(&functionHashTableInit, doInitFunctionHashTable); @@ -79,16 +91,17 @@ void qRemoveUdfInfo(uint64_t id, SUdfInfo* pUdfInfo) { bool isTagsQuery(SArray* pFunctionIdList) { int32_t num = (int32_t) taosArrayGetSize(pFunctionIdList); for (int32_t i = 0; i < num; ++i) { - int16_t f = *(int16_t*) taosArrayGet(pFunctionIdList, i); + char* f = *(char**) taosArrayGet(pFunctionIdList, i); + + // todo handle count(tbname) query + if (strcmp(f, "project") != 0 && strcmp(f, "count") != 0) { + return false; + } // "select count(tbname)" query // if (functId == FUNCTION_COUNT && pExpr->base.colpDesc->colId == TSDB_TBNAME_COLUMN_INDEX) { // continue; // } - - if (f != FUNCTION_TAGPRJ && f != FUNCTION_TID_TAG) { - return false; - } } return true; @@ -113,23 +126,13 @@ bool isTagsQuery(SArray* pFunctionIdList) { bool isProjectionQuery(SArray* pFunctionIdList) { int32_t num = (int32_t) taosArrayGetSize(pFunctionIdList); for (int32_t i = 0; i < num; ++i) { - int32_t f = *(int16_t*) taosArrayGet(pFunctionIdList, i); - if (f == FUNCTION_TS_DUMMY) { - continue; - } - - if (f != FUNCTION_PRJ && - f != FUNCTION_TAGPRJ && - f != FUNCTION_TAG && - f != FUNCTION_TS && - f != FUNCTION_ARITHM && - f != FUNCTION_DIFF && - f != FUNCTION_DERIVATIVE) { - return false; + char* f = *(char**) taosArrayGet(pFunctionIdList, i); + if (strcmp(f, "project") == 0) { + return true; } } - return true; + return false; } bool isDiffDerivativeQuery(SArray* pFunctionIdList) { @@ -190,11 +193,11 @@ bool isTopBotQuery(SArray* pFunctionIdList) { int32_t num = (int32_t) taosArrayGetSize(pFunctionIdList); for (int32_t i = 0; i < num; ++i) { char* f = *(char**) taosArrayGet(pFunctionIdList, i); - if (f == FUNCTION_TS) { + if (strcmp(f, "project") == 0) { continue; } - if (f == FUNCTION_TOP || f == FUNCTION_BOTTOM) { + if (strcmp(f, "top") == 0 || strcmp(f, "bottom") == 0) { return true; } } @@ -273,49 +276,26 @@ bool needReverseScan(SArray* pFunctionIdList) { return false; } -bool isSimpleAggregateRv(SArray* pFunctionIdList) { -// if (pQueryInfo->interval.interval > 0 || pQueryInfo->sessionWindow.gap > 0) { -// return false; -// } -// -// if (tscIsDiffDerivQuery(pQueryInfo)) { -// return false; -// } -// -// size_t numOfExprs = getNumOfExprs(pQueryInfo); -// for (int32_t i = 0; i < numOfExprs; ++i) { -// SExprInfo* pExpr = getExprInfo(pQueryInfo, i); -// if (pExpr == NULL) { -// continue; -// } -// -// int32_t functionId = pExpr->base.functionId; -// if (functionId < 0) { -// SUdfInfo* pUdfInfo = taosArrayGet(pQueryInfo->pUdfInfo, -1 * functionId - 1); -// if (pUdfInfo->funcType == TSDB_UDF_TYPE_AGGREGATE) { -// return true; -// } -// -// continue; -// } -// -// if (functionId == FUNCTION_TS || functionId == FUNCTION_TS_DUMMY) { -// continue; -// } -// -// if ((!IS_MULTIOUTPUT(aAggs[functionId].status)) || -// (functionId == FUNCTION_TOP || functionId == FUNCTION_BOTTOM || functionId == FUNCTION_TS_COMP)) { -// return true; -// } -// } +bool isAgg(SArray* pFunctionIdList) { + size_t size = taosArrayGetSize(pFunctionIdList); + for (int32_t i = 0; i < size; ++i) { + char* f = *(char**) taosArrayGet(pFunctionIdList, i); + if (strcmp(f, "project") == 0) { + return false; + } + + if (qIsAggregateFunction(f)) { + return true; + } + } return false; } bool isBlockDistQuery(SArray* pFunctionIdList) { int32_t num = (int32_t) taosArrayGetSize(pFunctionIdList); - int32_t f = *(int16_t*) taosArrayGet(pFunctionIdList, 0); - return (num == 1 && f == FUNCTION_BLKINFO); + char* f = *(char**) taosArrayGet(pFunctionIdList, 0); + return (num == 1 && strcmp(f, "block_dist") == 0); } bool isTwoStageSTableQuery(SArray* pFunctionIdList, int32_t tableIndex) { @@ -426,8 +406,9 @@ void extractFunctionDesc(SArray* pFunctionIdList, SMultiFunctionsDesc* pDesc) { return; } - pDesc->projectionQuery = isProjectionQuery(pFunctionIdList); - pDesc->onlyTagQuery = isTagsQuery(pFunctionIdList); +// pDesc->projectionQuery = isProjectionQuery(pFunctionIdList); +// pDesc->onlyTagQuery = isTagsQuery(pFunctionIdList); pDesc->interpQuery = isInterpQuery(pFunctionIdList); pDesc->topbotQuery = isTopBotQuery(pFunctionIdList); + pDesc->agg = isAgg(pFunctionIdList); } diff --git a/source/libs/parser/src/astValidate.c b/source/libs/parser/src/astValidate.c index 5d1ff936dd..d9fd822b9b 100644 --- a/source/libs/parser/src/astValidate.c +++ b/source/libs/parser/src/astValidate.c @@ -13,7 +13,6 @@ * along with this program. If not, see . */ -#include #include #include "astGenerator.h" #include "function.h" @@ -703,6 +702,8 @@ static int32_t parseSlidingClause(SQueryStmtInfo* pQueryInfo, SToken* pSliding, return TSDB_CODE_SUCCESS; } +static void setTsOutputExprInfo(SQueryStmtInfo* pQueryInfo, STableMetaInfo* pTableMetaInfo, int32_t outputIndex, int32_t tableIndex); + // validate the interval info int32_t validateIntervalNode(SQueryStmtInfo *pQueryInfo, SSqlNode* pSqlNode, SMsgBuf* pMsgBuf) { const char* msg1 = "sliding cannot be used without interval"; @@ -720,11 +721,6 @@ int32_t validateIntervalNode(SQueryStmtInfo *pQueryInfo, SSqlNode* pSqlNode, SMs } } - // orderby column not set yet, set it to be the primary timestamp column - if (pQueryInfo->order.orderColId == INT32_MIN) { - pQueryInfo->order.orderColId = PRIMARYKEY_TIMESTAMP_COL_ID; - } - // interval is not null SToken *t = &pSqlNode->interval.interval; if (parseNatualDuration(t->z, t->n, &pQueryInfo->interval.interval, @@ -753,6 +749,13 @@ int32_t validateIntervalNode(SQueryStmtInfo *pQueryInfo, SSqlNode* pSqlNode, SMs return TSDB_CODE_TSC_INVALID_OPERATION; } + if (tsCompatibleModel) { + SExprInfo* pFirstExpr = getExprInfo(pQueryInfo, 0); + if (pFirstExpr->pExpr->nodeType != TEXPR_FUNCTION_NODE || strcasecmp(pFirstExpr->pExpr->_function.functionName, "dummy") != 0) { + setTsOutputExprInfo(pQueryInfo, pTableMetaInfo, 0, 0); + } + } + // It is a time window query pQueryInfo->info.timewindow = true; return TSDB_CODE_SUCCESS; @@ -922,8 +925,6 @@ int32_t validateLimitNode(SQueryStmtInfo *pQueryInfo, SSqlNode* pSqlNode, SMsgBu } } -static void setTsOutputExprInfo(SQueryStmtInfo* pQueryInfo, STableMetaInfo* pTableMetaInfo, int32_t outputIndex, int32_t tableIndex); - int32_t validateOrderbyNode(SQueryStmtInfo *pQueryInfo, SSqlNode* pSqlNode, SMsgBuf* pMsgBuf) { const char* msg1 = "invalid column name in orderby clause"; const char* msg2 = "too many order by columns"; @@ -934,6 +935,8 @@ int32_t validateOrderbyNode(SQueryStmtInfo *pQueryInfo, SSqlNode* pSqlNode, SMsg return TSDB_CODE_SUCCESS; } + pQueryInfo->order = taosArrayInit(4, sizeof(SOrder)); + STableMetaInfo* pTableMetaInfo = getMetaInfo(pQueryInfo, 0); SArray* pSortOrder = pSqlNode->pSortOrder; @@ -944,40 +947,43 @@ int32_t validateOrderbyNode(SQueryStmtInfo *pQueryInfo, SSqlNode* pSqlNode, SMsg * for super table query, the order option must be less than 3. */ size_t size = taosArrayGetSize(pSortOrder); - if (UTIL_TABLE_IS_NORMAL_TABLE(pTableMetaInfo) || UTIL_TABLE_IS_TMP_TABLE(pTableMetaInfo)) { + if ((UTIL_TABLE_IS_NORMAL_TABLE(pTableMetaInfo) || UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) && (pQueryInfo->info.projectionQuery)) { if (size > 1) { return buildInvalidOperationMsg(pMsgBuf, msg3); } - } else { - if (size > 2) { - return buildInvalidOperationMsg(pMsgBuf, msg2); - } } // handle the first part of order by - SVariant* pVar = taosArrayGet(pSortOrder, 0); - SSchema s = {0}; - if (pVar->nType == TSDB_DATA_TYPE_BINARY) { - SColumnIndex index = COLUMN_INDEX_INITIALIZER; - SToken columnName = {pVar->nLen, pVar->nType, pVar->pz}; - if (getColumnIndexByName(&columnName, pQueryInfo, &index, pMsgBuf) != TSDB_CODE_SUCCESS) { - return buildInvalidOperationMsg(pMsgBuf, msg1); - } + for(int32_t i = 0; i < taosArrayGetSize(pSortOrder); ++i) { + SVariant* pVar = taosArrayGet(pSortOrder, i); + if (pVar->nType == TSDB_DATA_TYPE_BINARY) { + SColumn c = {0}; - s = *(SSchema*) getOneColumnSchema(pTableMetaInfo->pTableMeta, index.columnIndex); - } else { // order by [1|2|3] - if (pVar->i > getNumOfFields(&pQueryInfo->fieldsInfo)) { - return buildInvalidOperationMsg(pMsgBuf, msg4); - } + // find the orde column among the result field. + for (int32_t j = 0; j < getNumOfFields(&pQueryInfo->fieldsInfo); ++j) { + SInternalField* pInfo = taosArrayGet(pQueryInfo->fieldsInfo.internalField, j); + SSchema* pSchema = &pInfo->pExpr->base.resSchema; + if (strcasecmp(pVar->pz, pSchema->name) == 0) { + setColumn(&c, pTableMetaInfo->pTableMeta->uid, pTableMetaInfo->aliasName, TSDB_COL_TMP, &pSchema); + return TSDB_CODE_SUCCESS; + } + } - SExprInfo* pExprInfo = getExprInfo(pQueryInfo, pVar->i); - s = pExprInfo->base.resSchema; + return buildInvalidOperationMsg(pMsgBuf, "invalid order by column"); + } else { // order by [1|2|3] + if (pVar->i > getNumOfFields(&pQueryInfo->fieldsInfo)) { + return buildInvalidOperationMsg(pMsgBuf, msg4); + } + + int32_t index = pVar->i - 1; + SExprInfo* pExprInfo = getExprInfo(pQueryInfo, index); + + SOrder c = {0}; + setColumn(&c.col, pTableMetaInfo->pTableMeta->uid, pTableMetaInfo->aliasName, TSDB_COL_TMP, &pExprInfo->base.resSchema); + taosArrayPush(pQueryInfo->order, &c); + } } - SListItem* pItem = taosArrayGet(pSqlNode->pSortOrder, 0); - pQueryInfo->order.order = pItem->sortOrder; - pQueryInfo->order.orderColId = s.colId; - return TSDB_CODE_SUCCESS; } @@ -1378,6 +1384,8 @@ int32_t validateFillNode(SQueryStmtInfo *pQueryInfo, SSqlNode* pSqlNode, SMsgBuf return TSDB_CODE_SUCCESS; } +static void exprInfoPushDown(SQueryStmtInfo* pQueryInfo); + int32_t validateSqlNode(SSqlNode* pSqlNode, SQueryStmtInfo* pQueryInfo, SMsgBuf* pMsgBuf) { assert(pSqlNode != NULL && (pSqlNode->from == NULL || taosArrayGetSize(pSqlNode->from->list) > 0)); @@ -1529,11 +1537,6 @@ int32_t validateSqlNode(SSqlNode* pSqlNode, SQueryStmtInfo* pQueryInfo, SMsgBuf* return TSDB_CODE_TSC_INVALID_OPERATION; } - // set order by info - if (validateOrderbyNode(pQueryInfo, pSqlNode, pMsgBuf) != TSDB_CODE_SUCCESS) { - return TSDB_CODE_TSC_INVALID_OPERATION; - } - // set interval value if (validateIntervalNode(pQueryInfo, pSqlNode, pMsgBuf) != TSDB_CODE_SUCCESS) { return TSDB_CODE_TSC_INVALID_OPERATION; @@ -1558,6 +1561,11 @@ int32_t validateSqlNode(SSqlNode* pSqlNode, SQueryStmtInfo* pQueryInfo, SMsgBuf* return TSDB_CODE_SUCCESS; } + // set order by info + if (validateOrderbyNode(pQueryInfo, pSqlNode, pMsgBuf) != TSDB_CODE_SUCCESS) { + return TSDB_CODE_TSC_INVALID_OPERATION; + } + if ((code = validateLimitNode(pQueryInfo, pSqlNode, pMsgBuf)) != TSDB_CODE_SUCCESS) { return code; } @@ -1567,7 +1575,9 @@ int32_t validateSqlNode(SSqlNode* pSqlNode, SQueryStmtInfo* pQueryInfo, SMsgBuf* } } - for(int32_t i = 0; i < getExprFunctionLevel(pQueryInfo); ++i) { + exprInfoPushDown(pQueryInfo); + + for(int32_t i = 0; i < 1; ++i) { SArray* functionList = extractFunctionList(pQueryInfo->exprList[i]); extractFunctionDesc(functionList, &pQueryInfo->info); @@ -1579,6 +1589,87 @@ int32_t validateSqlNode(SSqlNode* pSqlNode, SQueryStmtInfo* pQueryInfo, SMsgBuf* return TSDB_CODE_SUCCESS; // Does not build query message here } +static bool isTagOrPrimaryTs(SExprInfo* pExprInfo) { + if (pExprInfo->pExpr->nodeType != TEXPR_COL_NODE) { + return false; + } + + assert(pExprInfo->base.pColumns->info.colId == pExprInfo->pExpr->pSchema->colId); + return (TSDB_COL_IS_TAG(pExprInfo->base.pColumns->flag) || pExprInfo->pExpr->pSchema->colId == PRIMARYKEY_TIMESTAMP_COL_ID); +} + +// todo extract the table column in expression + +static bool isGroupbyCol(SExprInfo* pExprInfo, SGroupbyExpr* pGroupbyExpr) { + assert(pExprInfo != NULL && pGroupbyExpr != NULL); + + int32_t nodeType = pExprInfo->pExpr->nodeType; + assert(nodeType == TEXPR_COL_NODE || nodeType == TEXPR_BINARYEXPR_NODE); + + for(int32_t i = 0; i < taosArrayGetSize(pGroupbyExpr->columnInfo); ++i) { + SColumn* pCol = taosArrayGet(pGroupbyExpr->columnInfo, i); + if (pCol->info.colId == pExprInfo->pExpr->pSchema->colId) { + return true; + } + } + + return false; +} + +static bool isAllAggExpr(SArray* pList) { + assert(pList != NULL); + + for (int32_t k = 0; k < taosArrayGetSize(pList); ++k) { + SExprInfo* p = taosArrayGetP(pList, k); + if (p->pExpr->nodeType != TEXPR_FUNCTION_NODE || !qIsAggregateFunction(p->pExpr->_function.functionName)) { + return false; + } + } + + return true; +} + +static SExprInfo* doCreateColumnNodeFromAggFunc(SSchema* pSchema); + +static void exprInfoPushDown(SQueryStmtInfo* pQueryInfo) { + assert(pQueryInfo != NULL); + + size_t level = getExprFunctionLevel(pQueryInfo); + for(int32_t i = 0; i < level - 1; ++i) { + SArray* p = pQueryInfo->exprList[i]; + + SArray* pNext = pQueryInfo->exprList[i + 1]; + if (!isAllAggExpr(pNext)) { + continue; + } + + for (int32_t j = 0; j < taosArrayGetSize(p); ++j) { + SExprInfo* pExpr = taosArrayGetP(p, j); + + if (pExpr->pExpr->nodeType == TEXPR_FUNCTION_NODE && qIsAggregateFunction(pExpr->pExpr->_function.functionName)) { + bool canPushDown = true; + for (int32_t k = 0; k < taosArrayGetSize(pNext); ++k) { + SExprInfo* pNextLevelExpr = taosArrayGetP(pNext, k); + if (pExpr->base.pColumns->info.colId == pNextLevelExpr->base.resSchema.colId) { + // pExpr is dependent on the output of the under layer, so it can not be push downwards + canPushDown = false; + break; + } + } + + if (canPushDown) { + taosArrayInsert(pNext, j, &pExpr); + taosArrayRemove(p, j); + + // todo add the project function in level of "i" + SExprInfo* pNew = doCreateColumnNodeFromAggFunc(&pExpr->base.resSchema); + taosArrayInsert(p, j, &pNew); + } + } + } + } +} + int32_t checkForInvalidExpr(SQueryStmtInfo* pQueryInfo, SMsgBuf* pMsgBuf) { assert(pQueryInfo != NULL && pMsgBuf != NULL); @@ -1597,9 +1688,18 @@ int32_t checkForInvalidExpr(SQueryStmtInfo* pQueryInfo, SMsgBuf* pMsgBuf) { // 1. invalid sql: // select top(col, k) from table_name [interval(1d)|session(ts, 1d)|statewindow(col)] order by k asc // order by normal column is not supported - int32_t colId = pQueryInfo->order.orderColId; - if (pQueryInfo->info.timewindow && colId != PRIMARYKEY_TIMESTAMP_COL_ID) { - return buildInvalidOperationMsg(pMsgBuf, msg2); + if (pQueryInfo->order != NULL) { + size_t numOfOrder = taosArrayGetSize(pQueryInfo->order); + if (numOfOrder > 1) { + return buildInvalidOperationMsg(pMsgBuf, msg2); + } + + if (numOfOrder > 0) { + SColumn* pOrderCol = taosArrayGet(pQueryInfo->order, 0); + if (pQueryInfo->info.timewindow && pOrderCol->info.colId != PRIMARYKEY_TIMESTAMP_COL_ID) { + return buildInvalidOperationMsg(pMsgBuf, msg2); + } + } } // select top(col, k) from table_name interval(10s) fill(prev) @@ -1609,14 +1709,25 @@ int32_t checkForInvalidExpr(SQueryStmtInfo* pQueryInfo, SMsgBuf* pMsgBuf) { } // select top(col, k), count(*) from table_name - int32_t num = 0; - SExprInfo* pMain = NULL; size_t size = getNumOfExprs(pQueryInfo); for (int32_t i = 0; i < size; ++i) { SExprInfo* pExpr = getExprInfo(pQueryInfo, i); - const char* functionName = pExpr->pExpr->_function.functionName; - if (strcmp(functionName, "top") != 0 && strcmp(functionName, "bottom") != 0) { + if (pExpr->pExpr->nodeType == TEXPR_COL_NODE) { + if (!isTagOrPrimaryTs(pExpr) && !isGroupbyCol(pExpr, &pQueryInfo->groupbyExpr)) { + return buildInvalidOperationMsg(pMsgBuf, "invalid expression in select clause"); + } + + } else if (pExpr->pExpr->nodeType == TEXPR_BINARYEXPR_NODE) { + continue; + // todo extract all column node in tree, and check for each node + + continue; + } + + // dummy column is also the placeholder for primary timestamp column in the result. + const char* functionName = pExpr->pExpr->_function.functionName; + if (strcmp(functionName, "top") != 0 && strcmp(functionName, "bottom") != 0 && strcmp(functionName, "dummy") != 0) { if (qIsAggregateFunction(functionName)) { return buildInvalidOperationMsg(pMsgBuf, "invalid expression in select clause"); } @@ -1709,6 +1820,35 @@ int32_t checkForInvalidExpr(SQueryStmtInfo* pQueryInfo, SMsgBuf* pMsgBuf) { pQueryInfo->info.groupbyColumn) { return buildInvalidOperationMsg(pMsgBuf, msg9); } + + /* + * 9. invalid sql: + * select count(*), col_name from table_name + */ + if (pQueryInfo->info.agg) { + bool isSelectivity = false; + + if (pQueryInfo->info.projectionQuery) { + size_t size = getNumOfExprs(pQueryInfo); + for (int32_t i = 0; i < size; ++i) { + SExprInfo* pExpr = getExprInfo(pQueryInfo, i); + if (pExpr->pExpr->nodeType == TEXPR_FUNCTION_NODE) { + if (!isSelectivity) { + isSelectivity = qIsSelectivityFunction(pExpr->pExpr->_function.functionName); + } + continue; + } + + if (isSelectivity && isTagOrPrimaryTs(pExpr)) { + continue; + } + + if (!isGroupbyCol(pExpr, &pQueryInfo->groupbyExpr)) { + return buildInvalidOperationMsg(pMsgBuf, "invalid expression in select"); + } + } + } + } } int32_t addResColumnInfo(SQueryStmtInfo* pQueryInfo, int32_t outputIndex, SSchema* pSchema, SExprInfo* pSqlExpr) { @@ -1856,7 +1996,7 @@ static void setTsOutputExprInfo(SQueryStmtInfo* pQueryInfo, STableMetaInfo* pTab SSourceParam param = {0}; addIntoSourceParam(¶m, NULL, &col); - SExprInfo* pExpr = createExprInfo(pTableMetaInfo, "ts_dummy", ¶m, &s, TSDB_KEYSIZE); + SExprInfo* pExpr = createExprInfo(pTableMetaInfo, "dummy", ¶m, &s, TSDB_KEYSIZE); strncpy(pExpr->base.token, "ts", tListLen(pExpr->base.token)); SArray* pExprList = getCurrentExprList(pQueryInfo); @@ -2695,6 +2835,7 @@ int32_t doAddOneProjectCol(SQueryStmtInfo* pQueryInfo, int32_t outputColIndex, S addResColumnInfo(pQueryInfo, exists, &pExpr->base.resSchema, pExpr); } + pQueryInfo->info.projectionQuery = true; return TSDB_CODE_SUCCESS; } @@ -2926,9 +3067,9 @@ static tExprNode* doCreateColumnNode(SQueryStmtInfo* pQueryInfo, SColumnIndex* p STableMeta* pTableMeta = pTableMetaInfo->pTableMeta; tExprNode* pExpr = calloc(1, sizeof(tExprNode)); - pExpr->nodeType = TEXPR_COL_NODE; - pExpr->pSchema = calloc(1, sizeof(SSchema)); + pExpr->nodeType = TEXPR_COL_NODE; + pExpr->pSchema = calloc(1, sizeof(SSchema)); SSchema* pSchema = NULL; if (pIndex->columnIndex == TSDB_TBNAME_COLUMN_INDEX) { @@ -2955,6 +3096,23 @@ static tExprNode* doCreateColumnNode(SQueryStmtInfo* pQueryInfo, SColumnIndex* p return pExpr; } +static SExprInfo* doCreateColumnNodeFromAggFunc(SSchema* pSchema) { + tExprNode* pExprNode = calloc(1, sizeof(tExprNode)); + + pExprNode->nodeType = TEXPR_COL_NODE; + pExprNode->pSchema = calloc(1, sizeof(SSchema)); + *(SSchema*)(pExprNode->pSchema) = *pSchema; + + SExprInfo* pExpr = calloc(1, sizeof(SExprInfo)); + if (pExpr == NULL) { + return NULL; + } + + pExpr->pExpr = pExprNode; + memcpy(&pExpr->base.resSchema, pSchema, sizeof(SSchema)); + return pExpr; +} + static int32_t validateSqlExpr(const tSqlExpr* pSqlExpr, SQueryStmtInfo *pQueryInfo, SMsgBuf* pMsgBuf); static int32_t doProcessFunctionLeafNodeParam(SQueryStmtInfo* pQueryInfo, int32_t* num, tExprNode*** p, SArray* pCols, @@ -3366,7 +3524,6 @@ int32_t validateSelectNodeList(SQueryStmtInfo* pQueryInfo, SArray* pSelNodeList, } else if (type == SQL_NODE_TABLE_COLUMN || type == SQL_NODE_VALUE) { // use the dynamic array list to decide if the function is valid or not // select table_name1.field_name1, table_name2.field_name2 from table_name1, table_name2 - // todo refacto to remove this function if ((code = addProjectionExprAndResColumn(pQueryInfo, pItem, outerQuery, pMsgBuf)) != TSDB_CODE_SUCCESS) { return code; } diff --git a/source/libs/parser/src/queryInfoUtil.c b/source/libs/parser/src/queryInfoUtil.c index a0afcf65c8..c548f1556a 100644 --- a/source/libs/parser/src/queryInfoUtil.c +++ b/source/libs/parser/src/queryInfoUtil.c @@ -325,12 +325,15 @@ SArray* extractFunctionList(SArray* pExprInfoList) { size_t len = taosArrayGetSize(pExprInfoList); SArray* p = taosArrayInit(len, POINTER_BYTES); + for(int32_t i = 0; i < len; ++i) { SExprInfo* pExprInfo = taosArrayGetP(pExprInfoList, i); if (pExprInfo->pExpr->nodeType == TEXPR_FUNCTION_NODE) { - taosArrayPush(p, &pExprInfo->pExpr->_function.functionName); + char* name = strdup(pExprInfo->pExpr->_function.functionName); + taosArrayPush(p, &name); } else { - taosArrayPush(p, "project"); + char* name = strdup("project"); + taosArrayPush(p, &name); } } diff --git a/source/libs/parser/test/parserTests.cpp b/source/libs/parser/test/parserTests.cpp index 5a240061b2..2193a44604 100644 --- a/source/libs/parser/test/parserTests.cpp +++ b/source/libs/parser/test/parserTests.cpp @@ -16,6 +16,7 @@ #include #include #include +#include "tglobal.h" #pragma GCC diagnostic ignored "-Wwrite-strings" #pragma GCC diagnostic ignored "-Wunused-function" @@ -422,8 +423,8 @@ TEST(testCase, function_Test10) { sqlCheck("select block_dist() + 20 from `t.1abc`", true); sqlCheck("select count(b), c from `t.1abc`", false); sqlCheck("select top(a, 20), count(b) from `t.1abc`", false); -// sqlCheck("select top(a, 20), b from `t.1abc`", false); -// sqlCheck("select top(a, 20), a+20 from `t.1abc`", true); + sqlCheck("select top(a, 20), b from `t.1abc`", false); + sqlCheck("select top(a, 20), a+20 from `t.1abc`", true); // sqlCheck("select top(a, 20), bottom(a, 10) from `t.1abc`", false); // sqlCheck("select last_row(*), count(b) from `t.1abc`", false); // sqlCheck("select last_row(a, b) + 20 from `t.1abc`", false); @@ -457,9 +458,14 @@ TEST(testCase, function_Test6) { ASSERT_EQ(ret, 0); SArray* pExprList = pQueryInfo->exprList[0]; - ASSERT_EQ(taosArrayGetSize(pExprList), 5); + if (tsCompatibleModel) { + ASSERT_EQ(taosArrayGetSize(pExprList), 6); + } else { + ASSERT_EQ(taosArrayGetSize(pExprList), 5); + } - SExprInfo* p1 = (SExprInfo*)taosArrayGetP(pExprList, 0); + int32_t index = tsCompatibleModel? 1:0; + SExprInfo* p1 = (SExprInfo*)taosArrayGetP(pExprList, index); ASSERT_EQ(p1->base.pColumns->uid, 110); ASSERT_EQ(p1->base.numOfParams, 0); ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_DOUBLE); @@ -477,9 +483,12 @@ TEST(testCase, function_Test6) { ASSERT_STREQ(pParam->pSchema->name, "t.1abc.a+b"); ASSERT_EQ(taosArrayGetSize(pQueryInfo->colList), 3); - ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 5); - SExprInfo* p2 = (SExprInfo*)taosArrayGetP(pExprList, 1); + int32_t numOfResCol = tsCompatibleModel? 6:5; + ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, numOfResCol); + + index = tsCompatibleModel? 2:1; + SExprInfo* p2 = (SExprInfo*)taosArrayGetP(pExprList, index); ASSERT_EQ(p2->base.pColumns->uid, 110); ASSERT_EQ(p2->base.numOfParams, 0); ASSERT_EQ(p2->base.resSchema.type, TSDB_DATA_TYPE_DOUBLE); @@ -527,9 +536,10 @@ TEST(testCase, function_Test6) { ASSERT_EQ(ret, 0); SArray* pExprList = pQueryInfo->exprList[0]; - ASSERT_EQ(taosArrayGetSize(pExprList), 2); + ASSERT_EQ(taosArrayGetSize(pExprList), 3); - SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 0); + int32_t index = tsCompatibleModel? 1:0; + SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, index); ASSERT_EQ(p1->base.pColumns->uid, 110); ASSERT_EQ(p1->base.numOfParams, 0); ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_BIGINT); @@ -553,7 +563,9 @@ TEST(testCase, function_Test6) { ASSERT_EQ(pParam->pSchema->colId, p2->base.resSchema.colId); ASSERT_EQ(taosArrayGetSize(pQueryInfo->colList), 3); - ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 2); + + int32_t numOfCols = tsCompatibleModel? 3:2; + ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, numOfCols); destroyQueryInfo(pQueryInfo); qParserClearupMetaRequestInfo(&req); diff --git a/source/libs/parser/test/plannerTest.cpp b/source/libs/parser/test/plannerTest.cpp index ee2c01dc48..cf8463f245 100644 --- a/source/libs/parser/test/plannerTest.cpp +++ b/source/libs/parser/test/plannerTest.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #pragma GCC diagnostic ignored "-Wwrite-strings" @@ -63,7 +64,6 @@ void setTableMetaInfo(SQueryStmtInfo* pQueryInfo, SMetaReq *req) { setSchema(&pSchema[1], TSDB_DATA_TYPE_INT, 4, "a", 1); setSchema(&pSchema[2], TSDB_DATA_TYPE_DOUBLE, 8, "b", 2); setSchema(&pSchema[3], TSDB_DATA_TYPE_DOUBLE, 8, "col", 3); - } void generateLogicplan(const char* sql) { @@ -132,7 +132,9 @@ TEST(testCase, planner_test) { ASSERT_EQ(ret, 0); SArray* pExprList = pQueryInfo->exprList[0]; - ASSERT_EQ(taosArrayGetSize(pExprList), 2); + + int32_t num = tsCompatibleModel? 2:1; + ASSERT_EQ(taosArrayGetSize(pExprList), num); SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 1); ASSERT_EQ(p1->base.pColumns->uid, 110); @@ -172,6 +174,7 @@ TEST(testCase, displayPlan) { generateLogicplan("select count(A+B) from `t.1abc` group by a"); generateLogicplan("select count(length(a)+b) from `t.1abc` group by a"); generateLogicplan("select count(*) from `t.1abc` interval(10s, 5s) sliding(7s)"); + generateLogicplan("select count(*) from `t.1abc` interval(10s, 5s) sliding(7s) order by 1 desc "); generateLogicplan("select count(*),sum(a),avg(b),min(a+b)+99 from `t.1abc`"); generateLogicplan("select count(*), min(a) + 99 from `t.1abc`"); generateLogicplan("select count(length(count(*) + 22)) from `t.1abc`"); @@ -180,7 +183,7 @@ TEST(testCase, displayPlan) { generateLogicplan("select count(*), first(a), last(b) from `t.1abc` session(ts, 20s)"); // order by + group by column + limit offset + fill - + generateLogicplan("select top(a, 20) k from `t.1abc` order by k asc limit 3 offset 1"); // join diff --git a/source/libs/planner/src/planner.c b/source/libs/planner/src/planner.c index 101ea3ec2f..8e53f231ef 100644 --- a/source/libs/planner/src/planner.c +++ b/source/libs/planner/src/planner.c @@ -46,14 +46,12 @@ typedef struct SJoinCond { static SArray* createQueryPlanImpl(SQueryStmtInfo* pQueryInfo); static void doDestroyQueryNode(SQueryPlanNode* pQueryNode); -static void exprInfoPushDown(SQueryStmtInfo* pQueryInfo); int32_t qOptimizeQueryPlan(struct SQueryPlanNode* pQueryNode) { return 0; } int32_t qCreateQueryPlan(const struct SQueryStmtInfo* pQueryInfo, struct SQueryPlanNode** pQueryNode) { - exprInfoPushDown((struct SQueryStmtInfo*) pQueryInfo); SArray* upstream = createQueryPlanImpl((struct SQueryStmtInfo*) pQueryInfo); assert(taosArrayGetSize(upstream) == 1); @@ -164,6 +162,12 @@ static SQueryPlanNode* createQueryNode(int32_t type, const char* name, SQueryPla memcpy(pNode->pExtInfo, pExtInfo, sizeof(SLimit)); break; } + + case QNODE_SORT: { + pNode->pExtInfo = taosArrayDup(pExtInfo); + break; + } + default: break; } @@ -267,6 +271,11 @@ static SQueryPlanNode* doCreateQueryPlanForSingleTableImpl(SQueryStmtInfo* pQuer pNode = createQueryNode(QNODE_FILL, "Fill", &pNode, 1, NULL, 0, pInfo); } + if (pQueryInfo->order != NULL) { + SArray* pList = pQueryInfo->exprList[0]; + pNode = createQueryNode(QNODE_SORT, "Sort", &pNode, 1, pList->pData, taosArrayGetSize(pList), pQueryInfo->order); + } + if (pQueryInfo->limit.limit != -1 || pQueryInfo->limit.offset != 0) { pNode = createQueryNode(QNODE_LIMIT, "Limit", &pNode, 1, NULL, 0, &pQueryInfo->limit); } @@ -306,44 +315,6 @@ static bool isAllAggExpr(SArray* pList) { return true; } -static void exprInfoPushDown(SQueryStmtInfo* pQueryInfo) { - assert(pQueryInfo != NULL); - - size_t level = getExprFunctionLevel(pQueryInfo); - for(int32_t i = 0; i < level - 1; ++i) { - SArray* p = pQueryInfo->exprList[i]; - - SArray* pNext = pQueryInfo->exprList[i + 1]; - if (!isAllAggExpr(pNext)) { - continue; - } - - for (int32_t j = 0; j < taosArrayGetSize(p); ++j) { - SExprInfo* pExpr = taosArrayGetP(p, j); - - if (pExpr->pExpr->nodeType == TEXPR_FUNCTION_NODE && qIsAggregateFunction(pExpr->pExpr->_function.functionName)) { - bool canPushDown = true; - for (int32_t k = 0; k < taosArrayGetSize(pNext); ++k) { - SExprInfo* pNextLevelExpr = taosArrayGetP(pNext, k); - if (pExpr->base.pColumns->info.colId == pNextLevelExpr->base.resSchema.colId) { - // pExpr is dependent on the output of the under layer, so it can not be push downwards - canPushDown = false; - break; - } - } - - if (canPushDown) { - taosArrayInsert(pNext, j, &pExpr); - taosArrayRemove(p, j); - - // todo add the project function in level of "i" - - } - } - } - } -} - SArray* createQueryPlanImpl(SQueryStmtInfo* pQueryInfo) { SArray* upstream = NULL; @@ -440,13 +411,13 @@ static int32_t doPrintPlan(char* buf, SQueryPlanNode* pQueryNode, int32_t level, switch(pQueryNode->info.type) { case QNODE_TABLESCAN: { - SQueryTableInfo* pInfo = (SQueryTableInfo*) pQueryNode->pExtInfo; - len1 = sprintf(buf + len, "%s #%" PRIu64 ") time_range: %" PRId64 " - %" PRId64, - pInfo->tableName, pInfo->uid, pInfo->window.skey, pInfo->window.ekey); + SQueryTableInfo* pInfo = (SQueryTableInfo*)pQueryNode->pExtInfo; + len1 = sprintf(buf + len, "%s #%" PRIu64 ") time_range: %" PRId64 " - %" PRId64, pInfo->tableName, pInfo->uid, + pInfo->window.skey, pInfo->window.ekey); assert(len1 > 0); len += len1; - for(int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { + for (int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { SColumn* pCol = taosArrayGetP(pQueryNode->pExpr, i); len1 = sprintf(buf + len, " [%s #%d] ", pCol->name, pCol->info.colId); @@ -467,7 +438,7 @@ static int32_t doPrintPlan(char* buf, SQueryPlanNode* pQueryNode, int32_t level, len += len1; - for(int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { + for (int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { SExprInfo* pExprInfo = taosArrayGetP(pQueryNode->pExpr, i); SSqlExpr* p = &pExprInfo->base; @@ -485,18 +456,18 @@ static int32_t doPrintPlan(char* buf, SQueryPlanNode* pQueryNode, int32_t level, len1 = sprintf(buf + len, ")"); len += len1; - //todo print filter info + // todo print filter info len1 = sprintf(buf + len, " filters:(nil)\n"); len += len1; break; } case QNODE_AGGREGATE: { - for(int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { + for (int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { SExprInfo* pExprInfo = taosArrayGetP(pQueryNode->pExpr, i); SSqlExpr* pExpr = &pExprInfo->base; - len += sprintf(buf + len,"%s [%s #%d]", pExpr->token, pExpr->resSchema.name, pExpr->resSchema.colId); + len += sprintf(buf + len, "%s [%s #%d]", pExpr->token, pExpr->resSchema.name, pExpr->resSchema.colId); if (i < pQueryNode->numOfExpr - 1) { len1 = sprintf(buf + len, ", "); len += len1; @@ -509,43 +480,43 @@ static int32_t doPrintPlan(char* buf, SQueryPlanNode* pQueryNode, int32_t level, } case QNODE_TIMEWINDOW: { - for(int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { + for (int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { SExprInfo* pExprInfo = taosArrayGetP(pQueryNode->pExpr, i); SSqlExpr* pExpr = &pExprInfo->base; - len += sprintf(buf + len,"%s [%s #%d]", pExpr->token, pExpr->resSchema.name, pExpr->resSchema.colId); + len += sprintf(buf + len, "%s [%s #%d]", pExpr->token, pExpr->resSchema.name, pExpr->resSchema.colId); if (i < pQueryNode->numOfExpr - 1) { - len1 = sprintf(buf + len,", "); + len1 = sprintf(buf + len, ", "); len += len1; } } - len1 = sprintf(buf + len,") "); + len1 = sprintf(buf + len, ") "); len += len1; SInterval* pInterval = pQueryNode->pExtInfo; // todo dynamic return the time precision len1 = sprintf(buf + len, "interval:%" PRId64 "(%s), sliding:%" PRId64 "(%s), offset:%" PRId64 "(%s)\n", - pInterval->interval, TSDB_TIME_PRECISION_MILLI_STR, pInterval->sliding, TSDB_TIME_PRECISION_MILLI_STR, - pInterval->offset, TSDB_TIME_PRECISION_MILLI_STR); + pInterval->interval, TSDB_TIME_PRECISION_MILLI_STR, pInterval->sliding, + TSDB_TIME_PRECISION_MILLI_STR, pInterval->offset, TSDB_TIME_PRECISION_MILLI_STR); len += len1; break; } case QNODE_STATEWINDOW: { - for(int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { + for (int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { SExprInfo* pExprInfo = taosArrayGetP(pQueryNode->pExpr, i); - SSqlExpr* pExpr = &pExprInfo->base; - len += sprintf(buf + len,"%s [%s #%d]", pExpr->token, pExpr->resSchema.name, pExpr->resSchema.colId); + SSqlExpr* pExpr = &pExprInfo->base; + len += sprintf(buf + len, "%s [%s #%d]", pExpr->token, pExpr->resSchema.name, pExpr->resSchema.colId); if (i < pQueryNode->numOfExpr - 1) { - len1 = sprintf(buf + len,", "); + len1 = sprintf(buf + len, ", "); len += len1; } } - len1 = sprintf(buf + len,") "); + len1 = sprintf(buf + len, ") "); len += len1; SColumn* pCol = pQueryNode->pExtInfo; @@ -555,44 +526,44 @@ static int32_t doPrintPlan(char* buf, SQueryPlanNode* pQueryNode, int32_t level, } case QNODE_SESSIONWINDOW: { - for(int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { + for (int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { SExprInfo* pExprInfo = taosArrayGetP(pQueryNode->pExpr, i); - SSqlExpr* pExpr = &pExprInfo->base; - len += sprintf(buf + len,"%s [%s #%d]", pExpr->token, pExpr->resSchema.name, pExpr->resSchema.colId); + SSqlExpr* pExpr = &pExprInfo->base; + len += sprintf(buf + len, "%s [%s #%d]", pExpr->token, pExpr->resSchema.name, pExpr->resSchema.colId); if (i < pQueryNode->numOfExpr - 1) { - len1 = sprintf(buf + len,", "); + len1 = sprintf(buf + len, ", "); len += len1; } } - len1 = sprintf(buf + len,") "); + len1 = sprintf(buf + len, ") "); len += len1; struct SSessionWindow* ps = pQueryNode->pExtInfo; - len1 = sprintf(buf + len, "col:[%s #%d], gap:%"PRId64" (ms) \n", ps->col.name, ps->col.info.colId, ps->gap); + len1 = sprintf(buf + len, "col:[%s #%d], gap:%" PRId64 " (ms) \n", ps->col.name, ps->col.info.colId, ps->gap); len += len1; break; } - case QNODE_GROUPBY: { // todo hide the invisible column - for(int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { + case QNODE_GROUPBY: { + for (int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { SExprInfo* pExprInfo = taosArrayGetP(pQueryNode->pExpr, i); SSqlExpr* pExpr = &pExprInfo->base; - len1 = sprintf(buf + len,"%s [%s #%d]", pExpr->token, pExpr->resSchema.name, pExpr->resSchema.colId); + len1 = sprintf(buf + len, "%s [%s #%d]", pExpr->token, pExpr->resSchema.name, pExpr->resSchema.colId); len += len1; if (i < pQueryNode->numOfExpr - 1) { - len1 = sprintf(buf + len,", "); + len1 = sprintf(buf + len, ", "); len += len1; } } SGroupbyExpr* pGroupbyExpr = pQueryNode->pExtInfo; - len1 = sprintf(buf + len,") groupby_col: "); + len1 = sprintf(buf + len, ") groupby_col: "); len += len1; - for(int32_t i = 0; i < taosArrayGetSize(pGroupbyExpr->columnInfo); ++i) { + for (int32_t i = 0; i < taosArrayGetSize(pGroupbyExpr->columnInfo); ++i) { SColumn* pCol = taosArrayGet(pGroupbyExpr->columnInfo, i); len1 = sprintf(buf + len, "[%s #%d] ", pCol->name, pCol->info.colId); len += len1; @@ -604,61 +575,78 @@ static int32_t doPrintPlan(char* buf, SQueryPlanNode* pQueryNode, int32_t level, case QNODE_FILL: { SFillEssInfo* pEssInfo = pQueryNode->pExtInfo; - len1 = sprintf(buf + len,"%d", pEssInfo->fillType); + len1 = sprintf(buf + len, "%d", pEssInfo->fillType); len += len1; if (pEssInfo->fillType == TSDB_FILL_SET_VALUE) { - len1 = sprintf(buf + len,", val:"); + len1 = sprintf(buf + len, ", val:"); len += len1; // todo get the correct fill data type - for(int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { - len1 = sprintf(buf + len,"%"PRId64, pEssInfo->val[i]); + for (int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { + len1 = sprintf(buf + len, "%" PRId64, pEssInfo->val[i]); len += len1; if (i < pQueryNode->numOfExpr - 1) { - len1 = sprintf(buf + len,", "); + len1 = sprintf(buf + len, ", "); len += len1; } } } - len1 = sprintf(buf + len,")\n"); + len1 = sprintf(buf + len, ")\n"); len += len1; break; } case QNODE_LIMIT: { SLimit* pVal = pQueryNode->pExtInfo; - len1 = sprintf(buf + len,"limit: %"PRId64", offset: %"PRId64")\n", pVal->limit, pVal->offset); + len1 = sprintf(buf + len, "limit: %" PRId64 ", offset: %" PRId64 ")\n", pVal->limit, pVal->offset); len += len1; break; } case QNODE_DISTINCT: case QNODE_TAGSCAN: { - len1 = sprintf(buf + len,"cols: "); + len1 = sprintf(buf + len, "cols: "); len += len1; - for(int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { + for (int32_t i = 0; i < pQueryNode->numOfExpr; ++i) { SExprInfo* pExprInfo = taosArrayGetP(pQueryNode->pExpr, i); - SSchema* resSchema = &pExprInfo->base.resSchema; + SSchema* resSchema = &pExprInfo->base.resSchema; - len1 = sprintf(buf + len,"[%s #%d]", resSchema->name, resSchema->colId); + len1 = sprintf(buf + len, "[%s #%d]", resSchema->name, resSchema->colId); len += len1; if (i < pQueryNode->numOfExpr - 1) { - len1 = sprintf(buf + len,", "); + len1 = sprintf(buf + len, ", "); len += len1; } } - len1 = sprintf(buf + len,")\n"); + len1 = sprintf(buf + len, ")\n"); len += len1; break; } + case QNODE_SORT: { + len1 = sprintf(buf + len, "cols:"); + len += len1; + + SArray* pSort = pQueryNode->pExtInfo; + for (int32_t i = 0; i < taosArrayGetSize(pSort); ++i) { + SOrder* p = taosArrayGet(pSort, i); + len1 = sprintf(buf + len, " [%s #%d %s]", p->col.name, p->col.info.colId, p->order == TSDB_ORDER_ASC? "ASC":"DESC"); + + len += len1; + } + + len1 = sprintf(buf + len, ")\n"); + len += len1; + break; + } + case QNODE_JOIN: { // print join condition len1 = sprintf(buf + len, ")\n");