[td-10564] 1. refactor and fix bug in order by validation. 2. Support the compatible model of ver. 2.0
This commit is contained in:
parent
fadd69c652
commit
bfd23c61d8
|
@ -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<SColumnInfoData>
|
||||
SArray *pTagsList; // SArray<SVariant> for tag value
|
||||
SDataBlockInfo info;
|
||||
SArray *pDataBlock; // SArray<SColumnInfoData>
|
||||
SArray *pConstantList; // SArray<SConstantItem>, 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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -4589,7 +4589,7 @@ SAggFunctionInfo aggFunc[35] = {{
|
|||
},
|
||||
{
|
||||
// 16
|
||||
"ts",
|
||||
"dummy",
|
||||
FUNCTION_TYPE_AGG,
|
||||
FUNCTION_TS,
|
||||
FUNCTION_TS,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <astGenerator.h>
|
||||
#include <function.h>
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <function.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <iostream>
|
||||
#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);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <function.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <tglobal.h>
|
||||
#include <iostream>
|
||||
#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
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue