提交 55f3ac17 编写于 作者: H Haojun Liao

[td-10564] refactor and add test cases.

上级 89e324c8
......@@ -68,6 +68,13 @@ typedef struct SColumnInfoData {
//======================================================================================================================
// the following structure shared by parser and executor
typedef struct SColumn {
uint64_t uid;
char name[TSDB_COL_NAME_LEN];
int8_t flag; // column type: normal column, tag, or user-input column (integer/float/string)
SColumnInfo info;
} SColumn;
typedef struct SLimit {
int64_t limit;
int64_t offset;
......@@ -89,8 +96,9 @@ typedef struct SGroupbyExpr {
typedef struct SSqlExpr {
char token[TSDB_COL_NAME_LEN]; // original token
SSchema resSchema;
SColIndex colInfo; // there may be mutiple input columns
uint64_t uid; // table uid, todo refactor use the pointer
int32_t numOfCols;
SColumn* pColumns; // data columns that are required by query
int32_t interBytes; // inter result buffer size
int16_t numOfParams; // argument value of each function
SVariant param[3]; // parameters are not more than 3
......
......@@ -161,6 +161,7 @@ enum {
TEXPR_NODE_DUMMY = 0x0,
TEXPR_BINARYEXPR_NODE= 0x1,
TEXPR_UNARYEXPR_NODE = 0x2,
TEXPR_FUNCTION_NODE = 0x3,
TEXPR_COL_NODE = 0x4,
TEXPR_VALUE_NODE = 0x8,
};
......@@ -169,10 +170,7 @@ typedef struct tExprNode {
uint8_t nodeType;
union {
struct {
union {
int32_t optr; // binary operator
int32_t functionId;// unary operator
};
void *info; // support filter operation on this expression only available for leaf node
struct tExprNode *pLeft; // left child pointer
struct tExprNode *pRight; // right child pointer
......@@ -180,16 +178,30 @@ typedef struct tExprNode {
SSchema *pSchema;// column node
struct SVariant *pVal; // value node
struct {// function node
char *functionName;
int32_t functionId;
int32_t num;
// Note that the attribute of pChild is not the parameter of function, it is the columns that involved in the
// calculation instead.
// E.g., Cov(col1, col2), the column information, w.r.t. the col1 and col2, is kept in pChild nodes.
// The concat function, concat(col1, col2), is a binary scalar
// operator and is kept in the attribute of _node.
struct tExprNode **pChild;
} _function;
};
} tExprNode;
//TODO create?
void exprTreeToBinary(SBufferWriter* bw, tExprNode* pExprTree);
void tExprTreeDestroy(tExprNode *pNode, void (*fp)(void *));
typedef struct SAggFunctionInfo {
char name[FUNCTIONS_NAME_MAX_LENGTH];
int8_t type; // Scalar function or aggregation function
uint8_t functionId; // Function Id
uint32_t functionId; // Function Id
int8_t sFunctionId; // Transfer function for super table query
uint16_t status;
......@@ -203,13 +215,13 @@ typedef struct SAggFunctionInfo {
int32_t (*dataReqFunc)(SQLFunctionCtx *pCtx, STimeWindow* w, int32_t colId);
} SAggFunctionInfo;
struct SScalarFuncParam;
typedef struct SScalarFunctionInfo {
char name[FUNCTIONS_NAME_MAX_LENGTH];
int8_t type; // scalar function or aggregation function
uint8_t functionId; // index of scalar function
bool (*init)(SQLFunctionCtx *pCtx, struct SResultRowEntryInfo* pResultCellInfo); // setup the execute environment
void (*addInput)(SQLFunctionCtx *pCtx);
uint32_t functionId; // index of scalar function
void (*process)(const struct SScalarFuncParam *pInput, struct SScalarFuncParam* pOutput);
} SScalarFunctionInfo;
typedef struct SMultiFunctionsDesc {
......@@ -241,7 +253,7 @@ int32_t getResultDataInfo(int32_t dataType, int32_t dataBytes, int32_t functionI
* @param len
* @return
*/
int32_t qIsBuiltinFunction(const char* name, int32_t len);
int32_t qIsBuiltinFunction(const char* name, int32_t len, bool* scalarFunction);
bool qIsValidUdf(SArray* pUdfInfo, const char* name, int32_t len, int32_t* functionId);
......
......@@ -26,29 +26,6 @@ extern "C" {
#include "tvariant.h"
#include "function.h"
typedef struct SColumn {
uint64_t tableUid;
int32_t columnIndex;
SColumnInfo info;
} SColumn;
//typedef struct SInterval {
// int32_t tz; // query client timezone
// char intervalUnit;
// char slidingUnit;
// char offsetUnit;
// int64_t interval;
// int64_t sliding;
// int64_t offset;
//} SInterval;
//
//typedef struct SSessionWindow {
// int64_t gap; // gap between two session window(in microseconds)
// int32_t primaryColId; // primary timestamp column
//} SSessionWindow;
typedef struct SField {
char name[TSDB_COL_NAME_LEN];
uint8_t type;
......@@ -89,12 +66,6 @@ typedef struct STagCond {
typedef struct STableMetaInfo {
STableMeta *pTableMeta; // table meta, cached in client side and acquired by name
SVgroupsInfo *vgroupList;
/*
* 1. keep the vgroup index during the multi-vnode super table projection query
* 2. keep the vgroup index for multi-vnode insertion
*/
int32_t vgroupIndex;
SName name;
char aliasName[TSDB_TABLE_NAME_LEN]; // alias name of table specified in query sql
SArray *tagColList; // SArray<SColumn*>, involved tag columns
......
......@@ -134,14 +134,14 @@ do { \
#define TSDB_BINARY_OP_REMAINDER 4004
#define TSDB_BINARY_OP_CONCAT 4005
#define TSDB_UNARY_OP_CEIL 4500
#define TSDB_UNARY_OP_FLOOR 4501
#define TSDB_UNARY_OP_ABS 4502
#define TSDB_UNARY_OP_ROUND 4503
#define TSDB_UNARY_OP_LEN 4600
#define TSDB_UNARY_OP_LTRIM 4601
#define TSDB_UNARY_OP_RTRIM 4601
#define FUNCTION_CEIL 4500
#define FUNCTION_FLOOR 4501
#define FUNCTION_ABS 4502
#define FUNCTION_ROUND 4503
#define FUNCTION_LENGTH 4800
#define FUNCTION_LTRIM 4801
#define FUNCTION_RTRIM 4802
#define IS_RELATION_OPTR(op) (((op) >= TSDB_RELATION_LESS) && ((op) < TSDB_RELATION_IN))
#define IS_ARITHMETIC_OPTR(op) (((op) >= TSDB_BINARY_OP_ADD) && ((op) <= TSDB_BINARY_OP_REMAINDER))
......
......@@ -1040,13 +1040,14 @@ static TSKEY getStartTsKey(SQueryAttr* pQueryAttr, STimeWindow* win, const TSKEY
}
static void doSetInputDataBlock(SOperatorInfo* pOperator, SQLFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t order);
static void doSetInputDataBlockInfo(SOperatorInfo* pOperator, SQLFunctionCtx* pCtx, SSDataBlock* pBlock, int32_t order) {
for (int32_t i = 0; i < pOperator->numOfOutput; ++i) {
pCtx[i].order = order;
pCtx[i].size = pBlock->info.rows;
pCtx[i].currentStage = (uint8_t)pOperator->pRuntimeEnv->scanFlag;
setBlockStatisInfo(&pCtx[i], pBlock, &pOperator->pExpr[i].base.colInfo);
setBlockStatisInfo(&pCtx[i], pBlock, NULL/*&pOperator->pExpr[i].base.colInfo*/);
}
}
......@@ -2358,8 +2359,8 @@ bool onlyQueryTags(SQueryAttr* pQueryAttr) {
if (functionId != FUNCTION_TAGPRJ &&
functionId != FUNCTION_TID_TAG &&
(!(functionId == FUNCTION_COUNT && pExprInfo->base.colInfo.colId == TSDB_TBNAME_COLUMN_INDEX)) &&
(!(functionId == FUNCTION_PRJ && TSDB_COL_IS_UD_COL(pExprInfo->base.colInfo.flag)))) {
(!(functionId == FUNCTION_COUNT && pExprInfo->base.pColumns->colId == TSDB_TBNAME_COLUMN_INDEX)) &&
(!(functionId == FUNCTION_PRJ && TSDB_COL_IS_UD_COL(pExprInfo->base.pColumns->flag)))) {
return false;
}
}
......@@ -2878,7 +2879,7 @@ static uint32_t doFilterByBlockTimeWindow(STableScanInfo* pTableScanInfo, SSData
int32_t numOfOutput = pTableScanInfo->numOfOutput;
for (int32_t i = 0; i < numOfOutput; ++i) {
int32_t functionId = pCtx[i].functionId;
int32_t colId = pTableScanInfo->pExpr[i].base.colInfo.colId;
int32_t colId = pTableScanInfo->pExpr[i].base.pColumns->colId;
// group by + first/last should not apply the first/last block filter
if (functionId < 0) {
......@@ -3205,12 +3206,12 @@ void setTagValue(SOperatorInfo* pOperatorInfo, void *pTable, SQLFunctionCtx* pCt
SExprInfo* pLocalExprInfo = &pExpr[idx];
// ts_comp column required the tag value for join filter
if (!TSDB_COL_IS_TAG(pLocalExprInfo->base.colInfo.flag)) {
if (!TSDB_COL_IS_TAG(pLocalExprInfo->base.pColumns->flag)) {
continue;
}
// todo use tag column index to optimize performance
doSetTagValueInParam(pTable, pLocalExprInfo->base.colInfo.colId, &pCtx[idx].tag, pLocalExprInfo->base.resSchema.type,
doSetTagValueInParam(pTable, pLocalExprInfo->base.pColumns->colId, &pCtx[idx].tag, pLocalExprInfo->base.resSchema.type,
pLocalExprInfo->base.resSchema.bytes);
if (IS_NUMERIC_TYPE(pLocalExprInfo->base.resSchema.type)
......@@ -5071,7 +5072,7 @@ SArray* getResultGroupCheckColumns(SQueryAttr* pQuery) {
int32_t functionId = getExprFunctionId(&pQuery->pExpr1[j]);
// FUNCTION_TAG_DUMMY function needs to be ignored
if (index->colId == pExpr->colInfo.colId &&
if (index->colId == pExpr->pColumns->info.colId &&
((TSDB_COL_IS_TAG(pExpr->colInfo.flag) && functionId == FUNCTION_TAG) ||
(TSDB_COL_IS_NORMAL_COL(pExpr->colInfo.flag) && functionId == FUNCTION_PRJ))) {
index->colIndex = j;
......@@ -5290,7 +5291,7 @@ SOperatorInfo *createOrderOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorI
pDataBlock->pDataBlock = taosArrayInit(numOfOutput, sizeof(SColumnInfoData));
for(int32_t i = 0; i < numOfOutput; ++i) {
SColumnInfoData col = {{0}};
col.info.colId = pExpr[i].base.colInfo.colId;
col.info.colId = pExpr[i].base.pColumns->colId;
// col.info.bytes = pExpr[i].base.colBytes;
// col.info.type = pExpr[i].base.colType;
taosArrayPush(pDataBlock->pDataBlock, &col);
......@@ -6776,7 +6777,7 @@ static SSDataBlock* doTagScan(void* param, bool* newgroup) {
int16_t type = pExprInfo->base.resSchema.type;
for(int32_t i = 0; i < pQueryAttr->numOfTags; ++i) {
if (pQueryAttr->tagColList[i].colId == pExprInfo->base.colInfo.colId) {
if (pQueryAttr->tagColList[i].colId == pExprInfo->base.pColumns->colId) {
bytes = pQueryAttr->tagColList[i].bytes;
type = pQueryAttr->tagColList[i].type;
break;
......@@ -6808,10 +6809,10 @@ static SSDataBlock* doTagScan(void* param, bool* newgroup) {
output += sizeof(pQueryAttr->vgId);
char* data = NULL;
if (pExprInfo->base.colInfo.colId == TSDB_TBNAME_COLUMN_INDEX) {
if (pExprInfo->base.pColumns->colId == TSDB_TBNAME_COLUMN_INDEX) {
data = tsdbGetTableName(item->pTable);
} else {
data = tsdbGetTableTagVal(item->pTable, pExprInfo->base.colInfo.colId, type, bytes);
data = tsdbGetTableTagVal(item->pTable, pExprInfo->base.pColumns->colId, type, bytes);
}
doSetTagValueToResultBuf(output, data, type, bytes);
......@@ -6839,7 +6840,7 @@ static SSDataBlock* doTagScan(void* param, bool* newgroup) {
int16_t type = 0, bytes = 0;
for(int32_t j = 0; j < pOperator->numOfOutput; ++j) {
// not assign value in case of user defined constant output column
if (TSDB_COL_IS_UD_COL(pExprInfo[j].base.colInfo.flag)) {
if (TSDB_COL_IS_UD_COL(pExprInfo[j].base.pColumns->flag)) {
continue;
}
......@@ -6847,10 +6848,10 @@ static SSDataBlock* doTagScan(void* param, bool* newgroup) {
type = pExprInfo[j].base.resSchema.type;
bytes = pExprInfo[j].base.resSchema.bytes;
if (pExprInfo[j].base.colInfo.colId == TSDB_TBNAME_COLUMN_INDEX) {
if (pExprInfo[j].base.pColumns->colId == TSDB_TBNAME_COLUMN_INDEX) {
data = tsdbGetTableName(item->pTable);
} else {
data = tsdbGetTableTagVal(item->pTable, pExprInfo[j].base.colInfo.colId, type, bytes);
data = tsdbGetTableTagVal(item->pTable, pExprInfo[j].base.pColumns->colId, type, bytes);
}
dst = pColInfo->pData + count * pExprInfo[j].base.resSchema.bytes;
......@@ -7310,9 +7311,9 @@ int32_t convertQueryMsg(SQueryTableMsg *pQueryMsg, SQueryParam* param) {
for (int32_t i = 0; i < pQueryMsg->numOfOutput; ++i) {
param->pExpr[i] = pExprMsg;
pExprMsg->colInfo.colIndex = htons(pExprMsg->colInfo.colIndex);
pExprMsg->colInfo.colId = htons(pExprMsg->colInfo.colId);
pExprMsg->colInfo.flag = htons(pExprMsg->colInfo.flag);
// pExprMsg->colInfo.colIndex = htons(pExprMsg->colInfo.colIndex);
// pExprMsg->colInfo.colId = htons(pExprMsg->colInfo.colId);
// pExprMsg->colInfo.flag = htons(pExprMsg->colInfo.flag);
// pExprMsg->colBytes = htons(pExprMsg->colBytes);
// pExprMsg->colType = htons(pExprMsg->colType);
......@@ -7361,9 +7362,9 @@ int32_t convertQueryMsg(SQueryTableMsg *pQueryMsg, SQueryParam* param) {
for (int32_t i = 0; i < pQueryMsg->secondStageOutput; ++i) {
param->pSecExpr[i] = pExprMsg;
pExprMsg->colInfo.colIndex = htons(pExprMsg->colInfo.colIndex);
pExprMsg->colInfo.colId = htons(pExprMsg->colInfo.colId);
pExprMsg->colInfo.flag = htons(pExprMsg->colInfo.flag);
// pExprMsg->colInfo.colIndex = htons(pExprMsg->colInfo.colIndex);
// pExprMsg->colInfo.colId = htons(pExprMsg->colInfo.colId);
// pExprMsg->colInfo.flag = htons(pExprMsg->colInfo.flag);
// pExprMsg->resType = htons(pExprMsg->resType);
// pExprMsg->resBytes = htons(pExprMsg->resBytes);
// pExprMsg->colBytes = htons(pExprMsg->colBytes);
......@@ -7677,11 +7678,11 @@ int32_t createQueryFunc(SQueriedTableInfo* pTableInfo, int32_t numOfOutput, SExp
SSchema s = {.type=TSDB_DATA_TYPE_BINARY, .bytes=TSDB_MAX_BINARY_LEN};
type = s.type;
bytes = s.bytes;
} else if (pExprs[i].base.colInfo.colId == TSDB_TBNAME_COLUMN_INDEX && functionId == FUNCTION_TAGPRJ) { // parse the normal column
} else if (pExprs[i].base.pColumns->info.colId == TSDB_TBNAME_COLUMN_INDEX && functionId == FUNCTION_TAGPRJ) { // parse the normal column
SSchema* s = tGetTbnameColumnSchema();
type = s->type;
bytes = s->bytes;
} else if (pExprs[i].base.colInfo.colId <= TSDB_UD_COLUMN_INDEX && pExprs[i].base.colInfo.colId > TSDB_RES_COL_ID) {
} else if (pExprs[i].base.pColumns->info.colId <= TSDB_UD_COLUMN_INDEX && pExprs[i].base.pColumns->info.colId > TSDB_RES_COL_ID) {
// it is a user-defined constant value column
assert(functionId == FUNCTION_PRJ);
......@@ -7692,7 +7693,7 @@ int32_t createQueryFunc(SQueriedTableInfo* pTableInfo, int32_t numOfOutput, SExp
}
} else {
int32_t j = getColumnIndexInSource(pTableInfo, &pExprs[i].base, pTagCols);
if (TSDB_COL_IS_TAG(pExprs[i].base.colInfo.flag)) {
if (TSDB_COL_IS_TAG(pExprs[i].base.pColumns->flag)) {
if (j < TSDB_TBNAME_COLUMN_INDEX || j >= pTableInfo->numOfTags) {
tfree(pExprs);
return TSDB_CODE_QRY_INVALID_MSG;
......@@ -7704,8 +7705,8 @@ int32_t createQueryFunc(SQueriedTableInfo* pTableInfo, int32_t numOfOutput, SExp
}
}
if (pExprs[i].base.colInfo.colId != TSDB_TBNAME_COLUMN_INDEX && j >= 0) {
SColumnInfo* pCol = (TSDB_COL_IS_TAG(pExprs[i].base.colInfo.flag))? &pTagCols[j]:&pTableInfo->colList[j];
if (pExprs[i].base.pColumns->info.colId != TSDB_TBNAME_COLUMN_INDEX && j >= 0) {
SColumnInfo* pCol = (TSDB_COL_IS_TAG(pExprs[i].base.pColumns->flag))? &pTagCols[j]:&pTableInfo->colList[j];
type = pCol->type;
bytes = pCol->bytes;
} else {
......@@ -7814,7 +7815,7 @@ int32_t createIndirectQueryFuncExprFromMsg(SQueryTableMsg* pQueryMsg, int32_t nu
// bytes = tDataTypes[type].bytes;
// } else {
// int32_t index = pExprs[i].base.colInfo.colIndex;
// assert(prevExpr[index].base.resSchema.colId == pExprs[i].base.colInfo.colId);
// assert(prevExpr[index].base.resSchema.colId == pExprs[i].base.pColumns->colId);
//
// type = prevExpr[index].base.resSchema.type;
// bytes = prevExpr[index].base.resSchema.bytes;
......@@ -8083,7 +8084,7 @@ SQInfo* createQInfoImpl(SQueryTableMsg* pQueryMsg, SGroupbyExpr* pGroupbyExpr, S
pQueryAttr->resultRowSize += pExprs[col].base.resSchema.bytes;
// keep the tag length
if (TSDB_COL_IS_TAG(pExprs[col].base.colInfo.flag)) {
if (TSDB_COL_IS_TAG(pExprs[col].base.pColumns->flag)) {
pQueryAttr->tagLen += pExprs[col].base.resSchema.bytes;
}
......
......@@ -37,7 +37,7 @@ typedef struct SScalarFunctionSupport {
char** data;
} SScalarFunctionSupport;
extern struct SScalarFunctionInfo scalarFunc[1];
extern struct SScalarFunctionInfo scalarFunc[5];
int32_t evaluateExprNodeTree(tExprNode* pExprs, int32_t numOfRows, SScalarFuncParam* pOutput,
void* param, char* (*getSourceDataBlock)(void*, const char*, int32_t));
......
......@@ -543,8 +543,8 @@ struct SFillColInfo* createFillColInfo(SExprInfo* pExpr, int32_t numOfOutput, co
pFillCol[i].col.offset = offset;
pFillCol[i].col.colId = pExprInfo->base.resSchema.colId;
pFillCol[i].tagIndex = -2;
pFillCol[i].flag = pExprInfo->base.colInfo.flag; // always be the normal column for table query
pFillCol[i].functionId = pExprInfo->pExpr->_node.functionId;
pFillCol[i].flag = pExprInfo->base.pColumns->flag; // always be the normal column for table query
pFillCol[i].functionId = pExprInfo->pExpr->_function.functionId;
pFillCol[i].fillVal.i = fillVal[i];
offset += pExprInfo->base.resSchema.bytes;
......
......@@ -30,11 +30,12 @@ static void doInitFunctionHashTable() {
static pthread_once_t functionHashTableInit = PTHREAD_ONCE_INIT;
int32_t qIsBuiltinFunction(const char* name, int32_t len) {
int32_t qIsBuiltinFunction(const char* name, int32_t len, bool* scalarFunction) {
pthread_once(&functionHashTableInit, doInitFunctionHashTable);
SAggFunctionInfo** pInfo = taosHashGet(functionHashTable, name, len);
if (pInfo != NULL) {
*scalarFunction = ((*pInfo)->type == FUNCTION_TYPE_SCALAR);
return (*pInfo)->functionId;
} else {
return -1;
......
......@@ -2,6 +2,156 @@
#include "tbinoperator.h"
#include "tunaryoperator.h"
static void assignBasicParaInfo(struct SScalarFuncParam* dst, const struct SScalarFuncParam* src) {
dst->type = src->type;
dst->bytes = src->bytes;
dst->num = src->num;
}
static void tceil(const SScalarFuncParam *pLeft, SScalarFuncParam* pOutput) {
assignBasicParaInfo(pOutput, pLeft);
switch (pLeft->bytes) {
case TSDB_DATA_TYPE_FLOAT: {
float* p = (float*) pLeft->data;
float* out = (float*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = ceilf(p[i]);
}
}
case TSDB_DATA_TYPE_DOUBLE: {
double* p = (double*) pLeft->data;
double* out = (double*)pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = ceil(p[i]);
}
}
default:
memcpy(pOutput->data, pLeft->data, pLeft->num* pLeft->bytes);
}
}
static void tfloor(const SScalarFuncParam *pLeft, SScalarFuncParam* pOutput) {
assignBasicParaInfo(pOutput, pLeft);
switch (pLeft->bytes) {
case TSDB_DATA_TYPE_FLOAT: {
float* p = (float*) pLeft->data;
float* out = (float*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = floorf(p[i]);
}
}
case TSDB_DATA_TYPE_DOUBLE: {
double* p = (double*) pLeft->data;
double* out = (double*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = floor(p[i]);
}
}
default:
memcpy(pOutput->data, pLeft->data, pLeft->num* pLeft->bytes);
}
}
static void _tabs(const SScalarFuncParam *pLeft, SScalarFuncParam* pOutput) {
assignBasicParaInfo(pOutput, pLeft);
switch (pLeft->bytes) {
case TSDB_DATA_TYPE_FLOAT: {
float* p = (float*) pLeft->data;
float* out = (float*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = (p[i] > 0)? p[i]:-p[i];
}
}
case TSDB_DATA_TYPE_DOUBLE: {
double* p = (double*) pLeft->data;
double* out = (double*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = (p[i] > 0)? p[i]:-p[i];
}
}
case TSDB_DATA_TYPE_TINYINT: {
int8_t* p = (int8_t*) pLeft->data;
int8_t* out = (int8_t*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = (p[i] > 0)? p[i]:-p[i];
}
}
case TSDB_DATA_TYPE_SMALLINT: {
int16_t* p = (int16_t*) pLeft->data;
int16_t* out = (int16_t*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = (p[i] > 0)? p[i]:-p[i];
}
}
case TSDB_DATA_TYPE_INT: {
int32_t* p = (int32_t*) pLeft->data;
int32_t* out = (int32_t*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = (p[i] > 0)? p[i]:-p[i];
}
}
case TSDB_DATA_TYPE_BIGINT: {
int64_t* p = (int64_t*) pLeft->data;
int64_t* out = (int64_t*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = (p[i] > 0)? p[i]:-p[i];
}
}
default:
memcpy(pOutput->data, pLeft->data, pLeft->num* pLeft->bytes);
}
}
static void tround(const SScalarFuncParam *pLeft, SScalarFuncParam* pOutput) {
assignBasicParaInfo(pOutput, pLeft);
switch (pLeft->bytes) {
case TSDB_DATA_TYPE_FLOAT: {
float* p = (float*) pLeft->data;
float* out = (float*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = roundf(p[i]);
}
}
case TSDB_DATA_TYPE_DOUBLE: {
double* p = (double*) pLeft->data;
double* out = (double*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = round(p[i]);
}
}
default:
memcpy(pOutput->data, pLeft->data, pLeft->num* pLeft->bytes);
}
}
static void tlength(const SScalarFuncParam *pLeft, SScalarFuncParam* pOutput) {
int64_t* out = (int64_t*) pOutput->data;
char* s = pLeft->data;
for(int32_t i = 0; i < pLeft->num; ++i) {
out[i] = varDataLen(POINTER_SHIFT(s, i * pLeft->bytes));
}
}
static void reverseCopy(char* dest, const char* src, int16_t type, int32_t numOfRows) {
switch(type) {
case TSDB_DATA_TYPE_TINYINT:
......@@ -168,11 +318,12 @@ int32_t evaluateExprNodeTree(tExprNode* pExprs, int32_t numOfRows, SScalarFuncPa
return 0;
}
SScalarFunctionInfo scalarFunc[1] = {
{
},
SScalarFunctionInfo scalarFunc[5] = {
{"ceil", FUNCTION_TYPE_SCALAR, FUNCTION_CEIL, tceil},
{"floor", FUNCTION_TYPE_SCALAR, FUNCTION_FLOOR, tfloor},
{"abs", FUNCTION_TYPE_SCALAR, FUNCTION_ABS, _tabs},
{"round", FUNCTION_TYPE_SCALAR, FUNCTION_ROUND, tround},
{"length", FUNCTION_TYPE_SCALAR, FUNCTION_LENGTH, tlength},
};
void setScalarFunctionSupp(struct SScalarFunctionSupport* sas, SExprInfo *pExprInfo, SSDataBlock* pSDataBlock) {
......
#include "tunaryoperator.h"
static void assignBasicParaInfo(struct SScalarFuncParam* dst, const struct SScalarFuncParam* src) {
dst->type = src->type;
dst->bytes = src->bytes;
dst->num = src->num;
}
static void tceil(SScalarFuncParam *pLeft, SScalarFuncParam* pOutput) {
assignBasicParaInfo(pOutput, pLeft);
switch (pLeft->bytes) {
case TSDB_DATA_TYPE_FLOAT: {
float* p = (float*) pLeft->data;
float* out = (float*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = ceilf(p[i]);
}
}
case TSDB_DATA_TYPE_DOUBLE: {
double* p = (double*) pLeft->data;
double* out = (double*)pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = ceil(p[i]);
}
}
default:
memcpy(pOutput->data, pLeft->data, pLeft->num* pLeft->bytes);
}
}
static void tfloor(SScalarFuncParam *pLeft, SScalarFuncParam* pOutput) {
assignBasicParaInfo(pOutput, pLeft);
switch (pLeft->bytes) {
case TSDB_DATA_TYPE_FLOAT: {
float* p = (float*) pLeft->data;
float* out = (float*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = floorf(p[i]);
}
}
case TSDB_DATA_TYPE_DOUBLE: {
double* p = (double*) pLeft->data;
double* out = (double*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = floor(p[i]);
}
}
default:
memcpy(pOutput->data, pLeft->data, pLeft->num* pLeft->bytes);
}
}
static void _tabs(SScalarFuncParam *pLeft, SScalarFuncParam* pOutput) {
assignBasicParaInfo(pOutput, pLeft);
switch (pLeft->bytes) {
case TSDB_DATA_TYPE_FLOAT: {
float* p = (float*) pLeft->data;
float* out = (float*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = (p[i] > 0)? p[i]:-p[i];
}
}
case TSDB_DATA_TYPE_DOUBLE: {
double* p = (double*) pLeft->data;
double* out = (double*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = (p[i] > 0)? p[i]:-p[i];
}
}
case TSDB_DATA_TYPE_TINYINT: {
int8_t* p = (int8_t*) pLeft->data;
int8_t* out = (int8_t*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = (p[i] > 0)? p[i]:-p[i];
}
}
case TSDB_DATA_TYPE_SMALLINT: {
int16_t* p = (int16_t*) pLeft->data;
int16_t* out = (int16_t*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = (p[i] > 0)? p[i]:-p[i];
}
}
case TSDB_DATA_TYPE_INT: {
int32_t* p = (int32_t*) pLeft->data;
int32_t* out = (int32_t*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = (p[i] > 0)? p[i]:-p[i];
}
}
case TSDB_DATA_TYPE_BIGINT: {
int64_t* p = (int64_t*) pLeft->data;
int64_t* out = (int64_t*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = (p[i] > 0)? p[i]:-p[i];
}
}
default:
memcpy(pOutput->data, pLeft->data, pLeft->num* pLeft->bytes);
}
}
static void tround(SScalarFuncParam *pLeft, SScalarFuncParam* pOutput) {
assignBasicParaInfo(pOutput, pLeft);
switch (pLeft->bytes) {
case TSDB_DATA_TYPE_FLOAT: {
float* p = (float*) pLeft->data;
float* out = (float*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = roundf(p[i]);
}
}
case TSDB_DATA_TYPE_DOUBLE: {
double* p = (double*) pLeft->data;
double* out = (double*) pOutput->data;
for (int32_t i = 0; i < pLeft->num; ++i) {
out[i] = round(p[i]);
}
}
default:
memcpy(pOutput->data, pLeft->data, pLeft->num* pLeft->bytes);
}
}
static void tlen(SScalarFuncParam *pLeft, SScalarFuncParam* pOutput) {
int64_t* out = (int64_t*) pOutput->data;
char* s = pLeft->data;
for(int32_t i = 0; i < pLeft->num; ++i) {
out[i] = varDataLen(POINTER_SHIFT(s, i * pLeft->bytes));
}
}
// TODO dynamic define these functions
_unary_scalar_fn_t getUnaryScalarOperatorFn(int32_t operator) {
switch(operator) {
case TSDB_UNARY_OP_CEIL:
return tceil;
case TSDB_UNARY_OP_FLOOR:
return tfloor;
case TSDB_UNARY_OP_ROUND:
return tround;
case TSDB_UNARY_OP_ABS:
return _tabs;
case TSDB_UNARY_OP_LEN:
return tlen;
default:
assert(0);
}
}
bool isStringOperatorFn(int32_t op) {
return op == TSDB_UNARY_OP_LEN;
return op == FUNCTION_LENGTH;
}
......@@ -38,6 +38,7 @@ extern "C" {
TAOS_FIELD createField(const SSchema* pSchema);
SSchema createSchema(uint8_t type, int16_t bytes, int16_t colId, const char* name);
void setColumn(SColumn* pColumn, uint64_t uid, const char* tableName, int8_t flag, const SSchema* pSchema);
SInternalField* insertFieldInfo(SFieldInfo* pFieldInfo, int32_t index, SSchema* field);
int32_t getNumOfFields(SFieldInfo* pFieldInfo);
......@@ -51,7 +52,7 @@ STableMetaInfo* addEmptyMetaInfo(SQueryStmtInfo* pQueryInfo);
void columnListCopyAll(SArray* dst, const SArray* src);
SColumn* columnListInsert(SArray* pColumnList, int32_t columnIndex, uint64_t uid, SSchema* pSchema);
SColumn* columnListInsert(SArray* pColumnList, uint64_t uid, SSchema* pSchema, int32_t flag);
SColumn* insertPrimaryTsColumn(SArray* pColumnList, uint64_t tableUid);
void cleanupTagCond(STagCond* pTagCond);
......
......@@ -327,7 +327,7 @@ static int32_t doValidateSubquery(SSqlNode* pSqlNode, int32_t index, SQueryStmtI
int32_t startOffset = (int32_t) taosArrayGetSize(pQueryInfo->colList);
for(int32_t i = 0; i < pMeta->tableInfo.numOfColumns; ++i) {
columnListInsert(pQueryInfo->colList, i + startOffset, pMeta->uid, &pMeta->schema[i]);
columnListInsert(pQueryInfo->colList, pMeta->uid, &pMeta->schema[i], TSDB_COL_NORMAL);
}
return TSDB_CODE_SUCCESS;
......@@ -556,14 +556,14 @@ int32_t validateGroupbyNode(SQueryStmtInfo* pQueryInfo, SArray* pList, SMsgBuf*
taosArrayPush(pGroupExpr->columnInfo, &colIndex);
index.columnIndex = relIndex;
columnListInsert(pTableMetaInfo->tagColList, index.columnIndex, pTableMeta->uid, pSchema);
columnListInsert(pTableMetaInfo->tagColList, pTableMeta->uid, pSchema, colIndex.flag);
} else {
// check if the column type is valid, here only support the bool/tinyint/smallint/bigint group by
if (pSchema->type == TSDB_DATA_TYPE_FLOAT || pSchema->type == TSDB_DATA_TYPE_DOUBLE) {
return buildInvalidOperationMsg(pMsgBuf, msg5);
}
columnListInsert(pQueryInfo->colList, index.columnIndex, pTableMeta->uid, pSchema);
columnListInsert(pQueryInfo->colList, pTableMeta->uid, pSchema, TSDB_COL_NORMAL);
SColIndex colIndex = { .colIndex = index.columnIndex, .flag = TSDB_COL_NORMAL, .colId = pSchema->colId };
strncpy(colIndex.name, pSchema->name, tListLen(colIndex.name));
......@@ -854,7 +854,7 @@ int32_t validateStateWindowNode(SQueryStmtInfo *pQueryInfo, SWindowStateVal* pWi
return buildInvalidOperationMsg(pMsgBuf, msg2);
}
columnListInsert(pQueryInfo->colList, index.columnIndex, pTableMeta->uid, pSchema);
columnListInsert(pQueryInfo->colList, pTableMeta->uid, pSchema, TSDB_COL_NORMAL);
SColIndex colIndex = { .colIndex = index.columnIndex, .flag = TSDB_COL_NORMAL, .colId = pSchema->colId };
//TODO use group by routine? state window query not support stable query.
......@@ -1114,7 +1114,7 @@ int32_t checkForInvalidOrderby(SQueryStmtInfo *pQueryInfo, SSqlNode* pSqlNode, S
pExpr = getExprInfo(pQueryInfo, pos);
// other tag are not allowed
if (pExpr->base.colInfo.colIndex != index.columnIndex && index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_ID) {
if (pExpr->base.pColumns->colIndex != index.columnIndex && index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_ID) {
return buildInvalidOperationMsg(pMsgBuf, msg5);
}
......@@ -1133,7 +1133,7 @@ int32_t checkForInvalidOrderby(SQueryStmtInfo *pQueryInfo, SSqlNode* pSqlNode, S
bool found = false;
for (int32_t i = 0; i < getNumOfExprs(pQueryInfo); ++i) {
SExprInfo* pExpr = getExprInfo(pQueryInfo, i);
if (getExprFunctionId(pExpr) == FUNCTION_PRJ && pExpr->base.colInfo.colId == PRIMARYKEY_TIMESTAMP_COL_ID) {
if (getExprFunctionId(pExpr) == FUNCTION_PRJ && pExpr->base.pColumns->colId == PRIMARYKEY_TIMESTAMP_COL_ID) {
found = true;
break;
}
......@@ -1214,7 +1214,7 @@ int32_t checkForInvalidOrderby(SQueryStmtInfo *pQueryInfo, SSqlNode* pSqlNode, S
pExpr = getExprInfo(pQueryInfo, pos);
if (pExpr->base.colInfo.colIndex != index.columnIndex && index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_ID) {
if (pExpr->base.pColumns->colIndex != index.columnIndex && index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_ID) {
return buildInvalidOperationMsg(pMsgBuf, msg5);
}
}
......@@ -1614,7 +1614,7 @@ int32_t checkForInvalidExpr(SQueryStmtInfo* pQueryInfo, SMsgBuf* pMsgBuf) {
for (int32_t i = 0; i < size; ++i) {
SExprInfo* pExpr = getExprInfo(pQueryInfo, i);
int32_t functionId = getExprFunctionId(pExpr);
if (functionId == FUNCTION_COUNT && TSDB_COL_IS_TAG(pExpr->base.colInfo.flag)) {
if (functionId == FUNCTION_COUNT && TSDB_COL_IS_TAG(pExpr->base.pColumns->flag)) {
return buildInvalidOperationMsg(pMsgBuf, msg1);
}
}
......@@ -1718,15 +1718,15 @@ SExprInfo* doAddOneExprInfo(SQueryStmtInfo* pQueryInfo, int32_t outputColIndex,
uint64_t uid = pTableMetaInfo->pTableMeta->uid;
SArray* p = TSDB_COL_IS_TAG(pIndex->type)?pTableMetaInfo->tagColList:pQueryInfo->colList;
columnListInsert(p, pIndex->columnIndex, uid, pColSchema);
columnListInsert(p, uid, pColSchema, pIndex->type);
pExpr->base.colInfo.flag = pIndex->type;
pExpr->base.pColumns->flag = pIndex->type;
if (TSDB_COL_IS_NORMAL_COL(pIndex->type)) {
insertPrimaryTsColumn(pQueryInfo->colList, uid);
}
if (finalResult) {
addResColumnInfo(pQueryInfo, outputColIndex, pColSchema, pExpr);
addResColumnInfo(pQueryInfo, outputColIndex, pResultSchema, pExpr);
}
return pExpr;
......@@ -1762,7 +1762,7 @@ static int32_t checkForAliasName(SMsgBuf* pMsgBuf, char* aliasName) {
}
static int32_t validateComplexExpr(tSqlExpr* pExpr, SQueryStmtInfo* pQueryInfo, SArray* pColList, int32_t* type, SMsgBuf* pMsgBuf);
static int32_t sqlExprToExprNode(tExprNode **pExpr, const tSqlExpr* pSqlExpr, SQueryStmtInfo* pQueryInfo, SArray* pCols, uint64_t *uid, SMsgBuf* pMsgBuf);
static int32_t sqlExprToExprNode(tExprNode **pExpr, const tSqlExpr* pSqlExpr, SQueryStmtInfo* pQueryInfo, SArray* pCols, SMsgBuf* pMsgBuf);
static int64_t getTickPerSecond(SVariant* pVariant, int32_t precision, int64_t* tickPerSec, SMsgBuf *pMsgBuf) {
const char* msg10 = "derivative duration should be greater than 1 Second";
......@@ -1795,7 +1795,7 @@ static void setTsOutputExprInfo(SQueryStmtInfo* pQueryInfo, STableMetaInfo* pTab
addExprInfo(pQueryInfo, outputIndex, pExpr);
SSchema* pSourceSchema = getOneColumnSchema(pTableMetaInfo->pTableMeta, indexTS.columnIndex);
columnListInsert(pQueryInfo->colList, indexTS.columnIndex, pTableMetaInfo->pTableMeta->uid, pSourceSchema);
columnListInsert(pQueryInfo->colList, pTableMetaInfo->pTableMeta->uid, pSourceSchema, TSDB_COL_NORMAL);
addResColumnInfo(pQueryInfo, outputIndex, &pExpr->base.resSchema, pExpr);
}
......@@ -1898,6 +1898,7 @@ static int32_t doHandleOneParam(SQueryStmtInfo *pQueryInfo, tSqlExprItem* pItem,
}
static int32_t multiColumnListInsert(SQueryStmtInfo* pQueryInfo, SArray* pColumnList, SMsgBuf* pMsgBuf);
static int32_t createComplexExpr(SQueryStmtInfo* pQueryInfo, int32_t exprIndex, tSqlExprItem* pItem, SMsgBuf* pMsgBuf);
int32_t extractFunctionParameterInfo(SQueryStmtInfo* pQueryInfo, int32_t tokenId, STableMetaInfo** pTableMetaInfo, SSchema* columnSchema,
tExprNode** pNode, SColumnIndex* pIndex, tSqlExprItem* pParamElem, SMsgBuf* pMsgBuf) {
......@@ -1906,8 +1907,31 @@ int32_t extractFunctionParameterInfo(SQueryStmtInfo* pQueryInfo, int32_t tokenId
const char* msg3 = "illegal column name";
const char* msg4 = "nested function is not supported";
const char* msg5 = "functions applied to tags are not allowed";
const char* msg6 = "aggregate function can not be nested in aggregate function";
const char* msg7 = "invalid function name";
if (tokenId == TK_ALL || tokenId == TK_ID) { // simple parameter
// simple parameter or nested function
// It is a parameter of a aggregate function, so it can not be still a aggregate function.
// E.g., the sql statement of "select count(count(*)) from table_name" is invalid.
tSqlExpr* pSqlExpr = pParamElem->pNode;
if (pParamElem->pNode->type == SQL_NODE_SQLFUNCTION) {
bool scalarFunc = false;
pParamElem->functionId = qIsBuiltinFunction(pSqlExpr->Expr.operand.z, pSqlExpr->Expr.operand.n, &scalarFunc);
if (pParamElem->functionId == FUNCTION_INVALID_ID) {
return buildInvalidOperationMsg(pMsgBuf, msg7);
}
if (!scalarFunc) {
return buildInvalidOperationMsg(pMsgBuf, msg6);
}
int32_t code = createComplexExpr(pQueryInfo, i, pParamElem, pMsgBuf);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
} else {
if ((getColumnIndexByName(&pParamElem->pNode->columnName, pQueryInfo, pIndex, pMsgBuf) != TSDB_CODE_SUCCESS)) {
return buildInvalidOperationMsg(pMsgBuf, msg3);
}
......@@ -1917,13 +1941,13 @@ int32_t extractFunctionParameterInfo(SQueryStmtInfo* pQueryInfo, int32_t tokenId
return buildInvalidOperationMsg(pMsgBuf, msg5);
}
*pTableMetaInfo = getMetaInfo(pQueryInfo, pIndex->tableIndex);
// 2. check if sql function can be applied on this column data type
*columnSchema = *(SSchema*) getOneColumnSchema((*pTableMetaInfo)->pTableMeta, pIndex->columnIndex);
} else if (tokenId == TK_PLUS || tokenId == TK_MINUS || tokenId == TK_STAR || tokenId == TK_REM || tokenId == TK_DIVIDE || tokenId == TK_CONCAT) {
*pTableMetaInfo = getMetaInfo(pQueryInfo, pIndex->tableIndex);
*columnSchema = *(SSchema*)getOneColumnSchema((*pTableMetaInfo)->pTableMeta, pIndex->columnIndex);
}
}else if (tokenId == TK_PLUS || tokenId == TK_MINUS || tokenId == TK_STAR || tokenId == TK_REM || tokenId == TK_DIVIDE || tokenId == TK_CONCAT) {
int32_t arithmeticType = NON_ARITHMEIC_EXPR;
SArray* pColumnList = taosArrayInit(4, sizeof(SColumnIndex));
SArray* pColumnList = taosArrayInit(4, sizeof(SColumn));
if (validateComplexExpr(pParamElem->pNode, pQueryInfo, pColumnList, &arithmeticType, pMsgBuf) != TSDB_CODE_SUCCESS) {
return buildInvalidOperationMsg(pMsgBuf, msg1);
}
......@@ -1940,7 +1964,7 @@ int32_t extractFunctionParameterInfo(SQueryStmtInfo* pQueryInfo, int32_t tokenId
tstrncpy(columnSchema->name, pExprToken->z, len);
SArray* colList = taosArrayInit(10, sizeof(SColIndex));
int32_t ret = sqlExprToExprNode(pNode, pParamElem->pNode, pQueryInfo, colList, NULL, pMsgBuf);
int32_t ret = sqlExprToExprNode(pNode, pParamElem->pNode, pQueryInfo, colList, pMsgBuf);
if (ret != TSDB_CODE_SUCCESS) {
taosArrayDestroy(colList);
tExprTreeDestroy(*pNode, NULL);
......@@ -2290,7 +2314,7 @@ int32_t addExprAndResColumn(SQueryStmtInfo* pQueryInfo, int32_t colIndex, tSqlEx
return buildInvalidOperationMsg(pMsgBuf, msg1);
}
columnListInsert(pTableMetaInfo->tagColList, index.columnIndex, pTableMetaInfo->pTableMeta->uid, &pSchema[index.columnIndex]);
columnListInsert(pTableMetaInfo->tagColList, pTableMetaInfo->pTableMeta->uid, &pSchema[index.columnIndex], TSDB_COL_TAG);
SSchema* pTagSchema = getTableTagSchema(pTableMetaInfo->pTableMeta);
SSchema s = {0};
......@@ -2337,6 +2361,8 @@ int32_t addExprAndResColumn(SQueryStmtInfo* pQueryInfo, int32_t colIndex, tSqlEx
return TSDB_CODE_SUCCESS;
}
default: {
// pUdfInfo = isValidUdf(pQueryInfo->pUdfInfo, pItem->pNode->Expr.operand.z, pItem->pNode->Expr.operand.n);
// if (pUdfInfo == NULL) {
......@@ -2380,6 +2406,110 @@ int32_t addExprAndResColumn(SQueryStmtInfo* pQueryInfo, int32_t colIndex, tSqlEx
return TSDB_CODE_TSC_INVALID_OPERATION;
}
static int32_t validateExprLeafColumnNode(SQueryStmtInfo *pQueryInfo, SToken* pColumnName, SArray* pList, SMsgBuf* pMsgBuf) {
SColumnIndex index = COLUMN_INDEX_INITIALIZER;
if (getColumnIndexByName(pColumnName, pQueryInfo, &index, pMsgBuf) != TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
// if column is timestamp not support arithmetic, so return invalid sql
STableMetaInfo* pTableMetaInfo = getMetaInfo(pQueryInfo, index.tableIndex);
STableMeta* pTableMeta = pTableMetaInfo->pTableMeta;
SSchema* pSchema = getOneColumnSchema(pTableMeta, index.columnIndex);
if (pSchema->type == TSDB_DATA_TYPE_TIMESTAMP) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
SColumn c = {0};
setColumn(&c, pTableMeta->uid, pTableMetaInfo->aliasName, index.type, pSchema);
taosArrayPush(pList, &c);
return TSDB_CODE_SUCCESS;
}
static int32_t validateExprLeafFunctionNode(SQueryStmtInfo* pQueryInfo, tSqlExpr* pExpr, SMsgBuf* pMsgBuf) {
tSqlExprItem item = {.pNode = pExpr, .aliasName = NULL};
// sql function list in selection clause.
// Append the sqlExpr into exprList of pQueryInfo structure sequentially
bool scalar = false;
item.functionId = qIsBuiltinFunction(pExpr->Expr.operand.z, pExpr->Expr.operand.n, &scalar);
if (item.functionId < 0) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
int32_t outputIndex = (int32_t)getNumOfExprs(pQueryInfo);
if (addExprAndResColumn(pQueryInfo, outputIndex, &item, false, pMsgBuf) != TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
// It is invalid in case of more than one sqlExpr, such as first(ts, k) - last(ts, k)
int32_t inc = (int32_t) getNumOfExprs(pQueryInfo) - outputIndex;
if (inc > 1) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
// Not supported data type in expression
for(int32_t i = 0; i < inc; ++i) {
SExprInfo* p1 = getExprInfo(pQueryInfo, i + outputIndex);
int16_t t = p1->base.resSchema.type;
if (t == TSDB_DATA_TYPE_TIMESTAMP) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
}
return TSDB_CODE_SUCCESS;
}
int32_t validateScalarFunctionParamNum(tSqlExprItem* pItem, SMsgBuf* pMsgBuf) {
int32_t code = TSDB_CODE_SUCCESS;
switch (pItem->functionId) {
case FUNCTION_CEIL: {
code = checkForkParam(pItem->pNode, 1, pMsgBuf);
break;
}
case FUNCTION_LENGTH: {
code = checkForkParam(pItem->pNode, 1, pMsgBuf);
break;
}
}
return code;
}
int32_t validateScalarFunctionParam(SQueryStmtInfo* pQueryInfo, tSqlExpr* pExpr, SArray* pList, int32_t* exprType, SMsgBuf* pMsgBuf) {
int32_t code = TSDB_CODE_SUCCESS;
// more than one parameter for count() function
SArray* pParamList = pExpr->Expr.paramList;
*exprType = NORMAL_ARITHMETIC;
for (int32_t i = 0; i < 1; ++i) {
tSqlExprItem* pParamElem = taosArrayGet(pParamList, i);
tSqlExpr* pSqlExpr = pParamElem->pNode;
int32_t type = pSqlExpr->type;
if (type == SQL_NODE_VALUE) {
} else if (type == SQL_NODE_SQLFUNCTION) {
code = validateExprLeafFunctionNode(pQueryInfo, pSqlExpr, pMsgBuf);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
} else if (type == SQL_NODE_EXPR) {
code = validateComplexExpr(pSqlExpr, pQueryInfo, pList, exprType, pMsgBuf);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
} else if (type == SQL_NODE_TABLE_COLUMN) {
code = validateExprLeafColumnNode(pQueryInfo, &pSqlExpr->columnName, pList, pMsgBuf);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
}
}
}
SExprInfo* doAddProjectCol(SQueryStmtInfo* pQueryInfo, int32_t outputColIndex, SColumnIndex* pColIndex, const char* aliasName, int32_t colId) {
STableMeta* pTableMeta = getMetaInfo(pQueryInfo, pColIndex->tableIndex)->pTableMeta;
......@@ -2452,6 +2582,48 @@ static SSchema createConstantColumnSchema(SVariant* pVal, const SToken* exprStr,
return s;
}
static int32_t handleTbnameProjection(SQueryStmtInfo* pQueryInfo, tSqlExprItem* pItem, SColumnIndex* pIndex, int32_t startPos, bool outerQuery, SMsgBuf* pMsgBuf) {
const char* msg3 = "tbname not allowed in outer query";
SSchema colSchema = {0};
int32_t functionId = 0;
if (outerQuery) { // todo??
STableMetaInfo* pTableMetaInfo = getMetaInfo(pQueryInfo, pIndex->tableIndex);
bool existed = false;
SSchema* pSchema = pTableMetaInfo->pTableMeta->schema;
int32_t numOfCols = getNumOfColumns(pTableMetaInfo->pTableMeta);
for (int32_t i = 0; i < numOfCols; ++i) {
if (strncasecmp(pSchema[i].name, TSQL_TBNAME_L, tListLen(pSchema[i].name)) == 0) {
existed = true;
pIndex->columnIndex = i;
break;
}
}
if (!existed) {
return buildInvalidOperationMsg(pMsgBuf, msg3);
}
colSchema = pSchema[pIndex->columnIndex];
functionId = FUNCTION_PRJ;
} else {
colSchema = *getTbnameColumnSchema();
functionId = FUNCTION_TAGPRJ;
}
SSchema resultSchema = colSchema;
resultSchema.colId = getNewResColId();
char rawName[TSDB_COL_NAME_LEN] = {0};
setTokenAndResColumnName(pItem, resultSchema.name, rawName, sizeof(colSchema.name) - 1);
doAddOneExprInfo(pQueryInfo, startPos, functionId, pIndex, &colSchema, &resultSchema, NULL, 0, rawName, true);
return TSDB_CODE_SUCCESS;
}
int32_t addProjectionExprAndResColumn(SQueryStmtInfo* pQueryInfo, tSqlExprItem* pItem, bool outerQuery, SMsgBuf* pMsgBuf) {
const char* msg1 = "tag for normal table query is not allowed";
const char* msg2 = "invalid column name";
......@@ -2487,7 +2659,7 @@ int32_t addProjectionExprAndResColumn(SQueryStmtInfo* pQueryInfo, tSqlExprItem*
if (pTableMeta->tableType != TSDB_TEMP_TABLE) {
insertPrimaryTsColumn(pQueryInfo->colList, pTableMeta->uid);
}
} else if (tokenId == TK_STRING || tokenId == TK_INTEGER || tokenId == TK_FLOAT) { // simple column projection query
} else if (tokenId == TK_STRING || tokenId == TK_INTEGER || tokenId == TK_FLOAT) { //constant value column
SColumnIndex index = createConstantColumnIndex(&pQueryInfo->udColumnId);
SSchema colSchema = createConstantColumnSchema(&pItem->pNode->value, &pItem->pNode->exprToken, pItem->aliasName);
......@@ -2498,49 +2670,14 @@ int32_t addProjectionExprAndResColumn(SQueryStmtInfo* pQueryInfo, tSqlExprItem*
// NOTE: the first parameter is reserved for the tag column id during join query process.
pExpr->base.numOfParams = 2;
taosVariantAssign(&pExpr->base.param[1], &pItem->pNode->value);
} else if (tokenId == TK_ID) {
} else if (tokenId == TK_ID) { // column name
SColumnIndex index = COLUMN_INDEX_INITIALIZER;
if (getColumnIndexByName(&pItem->pNode->columnName, pQueryInfo, &index, pMsgBuf) != TSDB_CODE_SUCCESS) {
return buildInvalidOperationMsg(pMsgBuf, msg2);
}
if (index.columnIndex == TSDB_TBNAME_COLUMN_INDEX) {
SSchema colSchema = {0};
int32_t functionId = 0;
if (outerQuery) { // todo??
STableMetaInfo* pTableMetaInfo = getMetaInfo(pQueryInfo, index.tableIndex);
bool existed = false;
SSchema* pSchema = pTableMetaInfo->pTableMeta->schema;
int32_t numOfCols = getNumOfColumns(pTableMetaInfo->pTableMeta);
for (int32_t i = 0; i < numOfCols; ++i) {
if (strncasecmp(pSchema[i].name, TSQL_TBNAME_L, tListLen(pSchema[i].name)) == 0) {
existed = true;
index.columnIndex = i;
break;
}
}
if (!existed) {
return buildInvalidOperationMsg(pMsgBuf, msg3);
}
colSchema = pSchema[index.columnIndex];
functionId = FUNCTION_PRJ;
} else {
colSchema = *getTbnameColumnSchema();
functionId = FUNCTION_TAGPRJ;
}
SSchema resultSchema = colSchema;
resultSchema.colId = getNewResColId();
char rawName[TSDB_COL_NAME_LEN] = {0};
setTokenAndResColumnName(pItem, resultSchema.name, rawName, sizeof(colSchema.name) - 1);
doAddOneExprInfo(pQueryInfo, startPos, functionId, &index, &colSchema, &resultSchema, NULL, 0, rawName, true);
handleTbnameProjection(pQueryInfo, pItem, &index, startPos, outerQuery, pMsgBuf);
} else {
STableMetaInfo* pTableMetaInfo = getMetaInfo(pQueryInfo, index.tableIndex);
if (TSDB_COL_IS_TAG(index.type) && UTIL_TABLE_IS_NORMAL_TABLE(pTableMetaInfo)) {
......@@ -2562,8 +2699,7 @@ int32_t addProjectionExprAndResColumn(SQueryStmtInfo* pQueryInfo, tSqlExprItem*
return TSDB_CODE_SUCCESS;
}
static int32_t validateExprLeafNode(tSqlExpr* pExpr, SQueryStmtInfo* pQueryInfo, SArray* pList, int32_t* type, uint64_t* uid,
SMsgBuf* pMsgBuf) {
static int32_t validateExprLeafNode(tSqlExpr* pExpr, SQueryStmtInfo* pQueryInfo, SArray* pList, int32_t* type, SMsgBuf* pMsgBuf) {
if (pExpr->type == SQL_NODE_TABLE_COLUMN) {
if (*type == NON_ARITHMEIC_EXPR) {
*type = NORMAL_ARITHMETIC;
......@@ -2571,21 +2707,10 @@ static int32_t validateExprLeafNode(tSqlExpr* pExpr, SQueryStmtInfo* pQueryInfo,
return TSDB_CODE_TSC_INVALID_OPERATION;
}
SColumnIndex index = COLUMN_INDEX_INITIALIZER;
if (getColumnIndexByName(&pExpr->columnName, pQueryInfo, &index, pMsgBuf) != TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
// if column is timestamp, bool, binary, nchar, not support arithmetic, so return invalid sql
STableMeta* pTableMeta = getMetaInfo(pQueryInfo, index.tableIndex)->pTableMeta;
SSchema* pSchema = getOneColumnSchema(pTableMeta, index.columnIndex);
if ((pSchema->type == TSDB_DATA_TYPE_TIMESTAMP) || (pSchema->type == TSDB_DATA_TYPE_BOOL) ||
(pSchema->type == TSDB_DATA_TYPE_BINARY) || (pSchema->type == TSDB_DATA_TYPE_NCHAR)) {
return TSDB_CODE_TSC_INVALID_OPERATION;
int32_t code = validateExprLeafColumnNode(pQueryInfo, &pExpr->columnName, pList, pMsgBuf);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
taosArrayPush(pList, &index);
} else if ((pExpr->tokenId == TK_FLOAT && (isnan(pExpr->value.d) || isinf(pExpr->value.d))) ||
pExpr->tokenId == TK_NULL) {
return TSDB_CODE_TSC_INVALID_OPERATION;
......@@ -2596,103 +2721,99 @@ static int32_t validateExprLeafNode(tSqlExpr* pExpr, SQueryStmtInfo* pQueryInfo,
return TSDB_CODE_TSC_INVALID_OPERATION;
}
tSqlExprItem item = {.pNode = pExpr, .aliasName = NULL};
// sql function list in selection clause.
// Append the sqlExpr into exprList of pQueryInfo structure sequentially
item.functionId = qIsBuiltinFunction(pExpr->Expr.operand.z, pExpr->Expr.operand.n);
if (item.functionId < 0) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
int32_t outputIndex = (int32_t)getNumOfExprs(pQueryInfo);
if (addExprAndResColumn(pQueryInfo, outputIndex, &item, false, pMsgBuf) != TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
// It is invalid in case of more than one sqlExpr, such as first(ts, k) - last(ts, k)
int32_t inc = (int32_t) getNumOfExprs(pQueryInfo) - outputIndex;
if (inc > 1) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
// Not supported data type in arithmetic expression
uint64_t id = -1;
for(int32_t i = 0; i < inc; ++i) {
SExprInfo* p1 = getExprInfo(pQueryInfo, i + outputIndex);
int16_t t = p1->base.resSchema.type;
if (IS_VAR_DATA_TYPE(t) || t == TSDB_DATA_TYPE_BOOL || t == TSDB_DATA_TYPE_TIMESTAMP) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
if (i == 0) {
id = p1->base.uid;
continue;
}
if (id != p1->base.uid) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
int32_t code = validateExprLeafFunctionNode(pQueryInfo, pExpr, pMsgBuf);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
*uid = id;
}
return TSDB_CODE_SUCCESS;
}
int32_t validateComplexExpr(tSqlExpr* pExpr, SQueryStmtInfo* pQueryInfo, SArray* pColList, int32_t* type, SMsgBuf* pMsgBuf) {
int32_t validateComplexExpr(tSqlExpr * pExpr, SQueryStmtInfo* pQueryInfo, SArray* pColList, int32_t* type, SMsgBuf* pMsgBuf) {
if (pExpr == NULL) {
return TSDB_CODE_SUCCESS;
}
tSqlExpr* pLeft = pExpr->pLeft;
uint64_t uidLeft = 0;
uint64_t uidRight = 0;
int32_t code = TSDB_CODE_SUCCESS;
if (pExpr->type == SQL_NODE_SQLFUNCTION) {
return validateScalarFunctionParam(pQueryInfo, pExpr, pColList, type, pMsgBuf);
}
tSqlExpr* pLeft = pExpr->pLeft;
if (pLeft->type == SQL_NODE_EXPR) {
int32_t ret = validateComplexExpr(pLeft, pQueryInfo, pColList, type, pMsgBuf);
if (ret != TSDB_CODE_SUCCESS) {
return ret;
code = validateComplexExpr(pLeft, pQueryInfo, pColList, type, pMsgBuf);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
} else {
int32_t ret = validateExprLeafNode(pLeft, pQueryInfo, pColList, type, &uidLeft, pMsgBuf);
if (ret != TSDB_CODE_SUCCESS) {
return ret;
code = validateExprLeafNode(pLeft, pQueryInfo, pColList, type, pMsgBuf);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
}
tSqlExpr* pRight = pExpr->pRight;
if (pRight->type == SQL_NODE_EXPR) {
int32_t ret = validateComplexExpr(pRight, pQueryInfo, pColList, type, pMsgBuf);
if (ret != TSDB_CODE_SUCCESS) {
return ret;
code = validateComplexExpr(pRight, pQueryInfo, pColList, type, pMsgBuf);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
} else {
int32_t ret = validateExprLeafNode(pRight, pQueryInfo, pColList, type, &uidRight, pMsgBuf);
if (ret != TSDB_CODE_SUCCESS) {
return ret;
code = validateExprLeafNode(pRight, pQueryInfo, pColList, type, pMsgBuf);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
}
// check divide by 0
if (pExpr->tokenId == TK_DIVIDE && pRight->type == SQL_NODE_VALUE) {
int32_t type1 = pRight->value.nType;
const char* msg1 = "invalid expr (divide by 0)";
if (type1 == TSDB_DATA_TYPE_DOUBLE && pRight->value.d < DBL_EPSILON) {
return buildInvalidOperationMsg(pMsgBuf, msg1);
} else if (type1 == TSDB_DATA_TYPE_INT && pRight->value.i == 0) {
return buildInvalidOperationMsg(pMsgBuf, msg1);
}
}
return TSDB_CODE_SUCCESS;
}
int32_t sqlExprToExprNode(tExprNode **pExpr, const tSqlExpr* pSqlExpr, SQueryStmtInfo* pQueryInfo, SArray* pCols, uint64_t *uid, SMsgBuf* pMsgBuf) {
int32_t sqlExprToExprNode(tExprNode **pExpr, const tSqlExpr* pSqlExpr, SQueryStmtInfo* pQueryInfo, SArray* pCols, SMsgBuf* pMsgBuf) {
tExprNode* pLeft = NULL;
tExprNode* pRight= NULL;
if (pSqlExpr->type == SQL_NODE_SQLFUNCTION) {
// assert it is a scalar function
*pExpr = calloc(1, sizeof(tExprNode));
(*pExpr)->nodeType = TEXPR_FUNCTION_NODE;
(*pExpr)->_function.num = 1;
(*pExpr)->_function.functionName = strndup(pSqlExpr->Expr.operand.z, pSqlExpr->Expr.operand.n);
SArray* pParamList = pSqlExpr->Expr.paramList;
size_t num = taosArrayGetSize(pParamList);
(*pExpr)->_function.pChild = calloc(num, POINTER_BYTES);
for(int32_t i = 0; i < num; ++i) {
tSqlExprItem* pItem = taosArrayGet(pParamList, i);
sqlExprToExprNode(&(((*pExpr)->_function.pChild)[0]), pItem->pNode, pQueryInfo, pCols, pMsgBuf);
}
return TSDB_CODE_SUCCESS;
}
SColumnIndex index = COLUMN_INDEX_INITIALIZER;
if (pSqlExpr->pLeft != NULL) {
int32_t ret = sqlExprToExprNode(&pLeft, pSqlExpr->pLeft, pQueryInfo, pCols, uid, pMsgBuf);
int32_t ret = sqlExprToExprNode(&pLeft, pSqlExpr->pLeft, pQueryInfo, pCols, pMsgBuf);
if (ret != TSDB_CODE_SUCCESS) {
return ret;
}
}
if (pSqlExpr->pRight != NULL) {
int32_t ret = sqlExprToExprNode(&pRight, pSqlExpr->pRight, pQueryInfo, pCols, uid, pMsgBuf);
int32_t ret = sqlExprToExprNode(&pRight, pSqlExpr->pRight, pQueryInfo, pCols, pMsgBuf);
if (ret != TSDB_CODE_SUCCESS) {
tExprTreeDestroy(pLeft, NULL);
return ret;
......@@ -2728,7 +2849,7 @@ int32_t sqlExprToExprNode(tExprNode **pExpr, const tSqlExpr* pSqlExpr, SQuerySt
}
return ret;
} else if (pSqlExpr->type == SQL_NODE_SQLFUNCTION) {
// arithmetic expression on the results of aggregation functions
// Expression on the results of aggregation functions
*pExpr = calloc(1, sizeof(tExprNode));
(*pExpr)->nodeType = TEXPR_COL_NODE;
(*pExpr)->pSchema = calloc(1, sizeof(SSchema));
......@@ -2737,19 +2858,28 @@ int32_t sqlExprToExprNode(tExprNode **pExpr, const tSqlExpr* pSqlExpr, SQuerySt
// set the input column data byte and type.
size_t size = taosArrayGetSize(pQueryInfo->exprList);
bool found = false;
uint64_t uid = 0;
for (int32_t i = 0; i < size; ++i) {
SExprInfo* p1 = taosArrayGetP(pQueryInfo->exprList, i);
if (strcmp((*pExpr)->pSchema->name, p1->base.resSchema.name) == 0) {
memcpy((*pExpr)->pSchema, &p1->base.resSchema, sizeof(SSchema));
if (uid != NULL) {
*uid = p1->base.uid;
}
found = true;
uid = p1->base.pColumns->uid;
break;
}
}
} else if (pSqlExpr->type == SQL_NODE_TABLE_COLUMN) { // column name, normal column arithmetic expression
assert(found);
if (pCols != NULL) { // record the involved columns
SColumn c = {0};
setColumn(&c, uid, NULL, TSDB_COL_NORMAL, (*pExpr)->pSchema);
taosArrayPush(pCols, &c);
}
} else if (pSqlExpr->type == SQL_NODE_TABLE_COLUMN) { // column name, normal column expression
int32_t ret = getColumnIndexByName(&pSqlExpr->columnName, pQueryInfo, &index, pMsgBuf);
if (ret != TSDB_CODE_SUCCESS) {
return ret;
......@@ -2764,17 +2894,6 @@ int32_t sqlExprToExprNode(tExprNode **pExpr, const tSqlExpr* pSqlExpr, SQuerySt
SSchema* pSchema = getOneColumnSchema(pTableMeta, index.columnIndex);
*(*pExpr)->pSchema = *pSchema;
if (pCols != NULL) { // record the involved columns
SColIndex colIndex = {0};
tstrncpy(colIndex.name, pSchema->name, sizeof(colIndex.name));
colIndex.colId = pSchema->colId;
colIndex.colIndex = index.columnIndex;
colIndex.flag = index.type;
taosArrayPush(pCols, &colIndex);
}
return TSDB_CODE_SUCCESS;
} else if (pSqlExpr->tokenId == TK_SET) {
int32_t colType = -1;
......@@ -2823,17 +2942,6 @@ int32_t sqlExprToExprNode(tExprNode **pExpr, const tSqlExpr* pSqlExpr, SQuerySt
assert((*pExpr)->_node.optr != 0);
// check for dividing by 0
if ((*pExpr)->_node.optr == TSDB_BINARY_OP_DIVIDE) {
if (pRight->nodeType == TEXPR_VALUE_NODE) {
if (pRight->pVal->nType == TSDB_DATA_TYPE_INT && pRight->pVal->i == 0) {
return buildInvalidOperationMsg(pMsgBuf, "invalid expr (divide by 0)");
} else if (pRight->pVal->nType == TSDB_DATA_TYPE_FLOAT && pRight->pVal->d == 0) {
return buildInvalidOperationMsg(pMsgBuf, "invalid expr (divide by 0)");
}
}
}
// NOTE: binary|nchar data allows the >|< type filter
if ((*pExpr)->_node.optr != TSDB_RELATION_EQUAL && (*pExpr)->_node.optr != TSDB_RELATION_NOT_EQUAL) {
if (pRight != NULL && pRight->nodeType == TEXPR_VALUE_NODE) {
......@@ -2848,33 +2956,32 @@ int32_t sqlExprToExprNode(tExprNode **pExpr, const tSqlExpr* pSqlExpr, SQuerySt
}
static int32_t multiColumnListInsert(SQueryStmtInfo* pQueryInfo, SArray* pColumnList, SMsgBuf* pMsgBuf) {
const char* msg3 = "tag columns can not be used in arithmetic expression";
const char* msg1 = "tag can not be used in expression";
SColumnIndex* p1 = taosArrayGet(pColumnList, 0);
STableMeta* pTableMeta = getMetaInfo(pQueryInfo, p1->tableIndex)->pTableMeta;
SColumn* p1 = taosArrayGet(pColumnList, 0);
size_t numOfNode = taosArrayGetSize(pColumnList);
for(int32_t k = 0; k < numOfNode; ++k) {
SColumnIndex* pIndex = taosArrayGet(pColumnList, k);
if (TSDB_COL_IS_TAG(pIndex->type)) {
return buildInvalidOperationMsg(pMsgBuf, msg3);
SColumn* p = taosArrayGet(pColumnList, k);
if (TSDB_COL_IS_TAG(p->flag)) {
return buildInvalidOperationMsg(pMsgBuf, msg1);
}
SSchema* ps = getOneColumnSchema(pTableMeta, pIndex->columnIndex);
columnListInsert(pQueryInfo->colList, pIndex->columnIndex, pTableMeta->uid, ps);
SSchema s = createSchema(p->info.type, p->info.bytes, p->info.colId, p->name);
columnListInsert(pQueryInfo->colList, p->uid, &s, p->flag);
}
insertPrimaryTsColumn(pQueryInfo->colList, pTableMeta->uid);
insertPrimaryTsColumn(pQueryInfo->colList, p1->uid);
return TSDB_CODE_SUCCESS;
}
static int32_t createComplexExpr(SQueryStmtInfo* pQueryInfo, int32_t exprIndex, tSqlExprItem* pItem, SMsgBuf* pMsgBuf) {
const char* msg1 = "invalid column name, illegal column type, or columns in arithmetic expression from two tables";
const char* msg1 = "invalid column name, illegal column type, or columns in expression from two tables";
const char* msg2 = "invalid arithmetic expression in select clause";
const char* msg3 = "tag columns can not be used in arithmetic expression";
int32_t arithmeticType = NON_ARITHMEIC_EXPR;
SArray* pColumnList = taosArrayInit(4, sizeof(SColumnIndex));
SArray* pColumnList = taosArrayInit(4, sizeof(SColumn));
if (validateComplexExpr(pItem->pNode, pQueryInfo, pColumnList, &arithmeticType, pMsgBuf) != TSDB_CODE_SUCCESS) {
return buildInvalidOperationMsg(pMsgBuf, msg1);
}
......@@ -2884,8 +2991,8 @@ static int32_t createComplexExpr(SQueryStmtInfo* pQueryInfo, int32_t exprIndex,
SSchema s = createSchema(TSDB_DATA_TYPE_DOUBLE, sizeof(double), getNewResColId(), "");
tExprNode* pNode = NULL;
SArray* colList = taosArrayInit(10, sizeof(SColIndex));
int32_t ret = sqlExprToExprNode(&pNode, pItem->pNode, pQueryInfo, colList, NULL, pMsgBuf);
SArray* colList = taosArrayInit(10, sizeof(SColumn));
int32_t ret = sqlExprToExprNode(&pNode, pItem->pNode, pQueryInfo, colList, pMsgBuf);
if (ret != TSDB_CODE_SUCCESS) {
taosArrayDestroy(colList);
tExprTreeDestroy(pNode, NULL);
......@@ -2924,13 +3031,13 @@ static int32_t createComplexExpr(SQueryStmtInfo* pQueryInfo, int32_t exprIndex,
tbufCloseWriter(&bw);
taosArrayDestroy(colList);
} else {
SColumnIndex columnIndex = {0};
SSchema s = createSchema(TSDB_DATA_TYPE_DOUBLE, sizeof(double), getNewResColId(), "");
addResColumnInfo(pQueryInfo, exprIndex, &s, NULL);
assert(taosArrayGetSize(pColumnList) == 0);
tExprNode* pNode = NULL;
int32_t ret = sqlExprToExprNode(&pNode, pItem->pNode, pQueryInfo, NULL, NULL, pMsgBuf);
int32_t ret = sqlExprToExprNode(&pNode, pItem->pNode, pQueryInfo, pColumnList, pMsgBuf);
if (ret != TSDB_CODE_SUCCESS) {
tExprTreeDestroy(pNode, NULL);
return buildInvalidOperationMsg(pMsgBuf, "invalid expression in select clause");
......@@ -2938,10 +3045,19 @@ static int32_t createComplexExpr(SQueryStmtInfo* pQueryInfo, int32_t exprIndex,
SExprInfo* pExpr = createBinaryExprInfo(pNode, &s);
addExprInfo(pQueryInfo, exprIndex, pExpr);
setTokenAndResColumnName(pItem, pExpr->base.resSchema.name, pExpr->base.token, TSDB_COL_NAME_LEN);
pExpr->base.numOfParams = 1;
// extract columns according to the tExprNode tree
size_t num = taosArrayGetSize(pColumnList);
pExpr->base.pColumns = calloc(num, sizeof(SColumn));
for(int32_t i = 0; i < num; ++i) {
pExpr->base.pColumns[i] = *(SColumn*) taosArrayGet(pColumnList, i);
}
pExpr->base.numOfCols = num;
pExpr->base.numOfParams = 1;
SBufferWriter bw = tbufInitWriter(NULL, false);
// TRY(0) {
exprTreeToBinary(&bw, pExpr->pExpr);
......@@ -2979,6 +3095,7 @@ int32_t validateSelectNodeList(SQueryStmtInfo* pQueryInfo, SArray* pSelNodeList,
return buildInvalidOperationMsg(pMsgBuf, msg1);
}
int32_t code = TSDB_CODE_SUCCESS;
size_t numOfExpr = taosArrayGetSize(pSelNodeList);
for (int32_t i = 0; i < numOfExpr; ++i) {
......@@ -2987,15 +3104,17 @@ int32_t validateSelectNodeList(SQueryStmtInfo* pQueryInfo, SArray* pSelNodeList,
int32_t type = pItem->pNode->type;
if (pItem->distinct) {
if (i != 0/* || type == SQL_NODE_SQLFUNCTION || type == SQL_NODE_EXPR*/) {
if (i != 0 || type == SQL_NODE_SQLFUNCTION || type == SQL_NODE_EXPR) {
return buildInvalidOperationMsg(pMsgBuf, msg4);
}
pQueryInfo->info.distinct = true;
}
bool scalarFunc = false;
if (type == SQL_NODE_SQLFUNCTION) {
pItem->functionId = qIsBuiltinFunction(pItem->pNode->Expr.operand.z, pItem->pNode->Expr.operand.n);
pItem->functionId = qIsBuiltinFunction(pItem->pNode->Expr.operand.z, pItem->pNode->Expr.operand.n, &scalarFunc);
if (pItem->functionId == FUNCTION_INVALID_ID) {
int32_t functionId = FUNCTION_INVALID_ID;
bool valid = qIsValidUdf(pQueryInfo->pUdfInfo, pItem->pNode->Expr.operand.z, pItem->pNode->Expr.operand.n, &functionId);
......@@ -3004,21 +3123,24 @@ int32_t validateSelectNodeList(SQueryStmtInfo* pQueryInfo, SArray* pSelNodeList,
}
pItem->functionId = functionId;
} else if (scalarFunc) {
if ((code = createComplexExpr(pQueryInfo, i, pItem, pMsgBuf)) != TSDB_CODE_SUCCESS) {
return code;
}
}
// sql function in selection clause, append sql function info in pSqlCmd structure sequentially
if (addExprAndResColumn(pQueryInfo, outputIndex, pItem, true, pMsgBuf) != TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
if ((code = addExprAndResColumn(pQueryInfo, outputIndex, pItem, true, pMsgBuf)) != TSDB_CODE_SUCCESS) {
return code;
}
} 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
if (addProjectionExprAndResColumn(pQueryInfo, pItem, outerQuery, pMsgBuf) != TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
if ((code = addProjectionExprAndResColumn(pQueryInfo, pItem, outerQuery, pMsgBuf)) != TSDB_CODE_SUCCESS) {
return code;
}
} else if (type == SQL_NODE_EXPR) {
int32_t code = createComplexExpr(pQueryInfo, i, pItem, pMsgBuf);
if (code != TSDB_CODE_SUCCESS) {
if ((code = createComplexExpr(pQueryInfo, i, pItem, pMsgBuf)) != TSDB_CODE_SUCCESS) {
return code;
}
} else {
......
......@@ -177,7 +177,8 @@ int32_t qParserExtractRequestedMetaInfo(const SSqlInfo* pSqlInfo, SMetaReq* pMet
}
// Let's assume that it is an UDF/UDAF, if it is not a built-in function.
if (qIsBuiltinFunction(t->z, t->n) < 0) {
bool scalarFunc = false;
if (qIsBuiltinFunction(t->z, t->n, &scalarFunc) < 0) {
char* fname = strndup(t->z, t->n);
taosArrayPush(pMetaInfo->pUdf, &fname);
}
......
......@@ -513,6 +513,20 @@ SSchema createSchema(uint8_t type, int16_t bytes, int16_t colId, const char* nam
return s;
}
void setColumn(SColumn* pColumn, uint64_t uid, const char* tableName, int8_t flag, const SSchema* pSchema) {
pColumn->uid = uid;
pColumn->flag = flag;
pColumn->info.colId = pSchema->colId;
pColumn->info.bytes = pSchema->bytes;
pColumn->info.type = pSchema->type;
if (tableName != NULL) {
snprintf(pColumn->name, tListLen(pColumn->name), "%s.%s", tableName, pSchema->name);
} else {
tstrncpy(pColumn->name, pSchema->name, tListLen(pColumn->name));
}
}
int32_t getNumOfFields(SFieldInfo* pFieldInfo) {
return pFieldInfo->numOfOutput;
}
......@@ -701,7 +715,7 @@ int32_t columnExists(SArray* pColumnList, int32_t columnId, uint64_t uid) {
int32_t i = 0;
while (i < numOfCols) {
SColumn* pCol = taosArrayGetP(pColumnList, i);
if ((pCol->info.colId != columnId) || (pCol->tableUid != uid)) {
if ((pCol->info.colId != columnId) || (pCol->uid != uid)) {
++i;
continue;
} else {
......@@ -716,64 +730,60 @@ int32_t columnExists(SArray* pColumnList, int32_t columnId, uint64_t uid) {
return i;
}
SColumn* columnListInsert(SArray* pColumnList, int32_t columnIndex, uint64_t uid, SSchema* pSchema) {
// ignore the tbname columnIndex to be inserted into source list
if (columnIndex < 0) {
return NULL;
}
static int32_t doFindPosition(const SArray* pColumnList, uint64_t uid, const SSchema* pSchema) {
int32_t i = 0;
size_t numOfCols = taosArrayGetSize(pColumnList);
int32_t i = 0;
while (i < numOfCols) {
SColumn* pCol = taosArrayGetP(pColumnList, i);
if (pCol->columnIndex < columnIndex) {
i++;
} else if (pCol->tableUid < uid) {
if (pCol->uid < uid) {
i++;
} else {
break;
continue;
}
if (pCol->info.colId < pSchema->colId) {
i++;
continue;
}
if (i >= numOfCols || numOfCols == 0) {
SColumn* b = calloc(1, sizeof(SColumn));
if (b == NULL) {
return NULL;
break;
}
b->columnIndex = columnIndex;
b->tableUid = uid;
b->info.colId = pSchema->colId;
b->info.bytes = pSchema->bytes;
b->info.type = pSchema->type;
return i;
}
taosArrayInsert(pColumnList, i, &b);
} else {
SColumn* columnListInsert(SArray* pColumnList, uint64_t uid, SSchema* pSchema, int32_t flag) {
// ignore the tbname columnIndex to be inserted into source list
assert(pSchema != NULL && pColumnList != NULL);
int32_t i = doFindPosition(pColumnList, uid, pSchema);
size_t size = taosArrayGetSize(pColumnList);
if (size > 0 && i < size) {
SColumn* pCol = taosArrayGetP(pColumnList, i);
if (pCol->uid == uid && pCol->info.colId == pSchema->colId) {
return pCol;
}
}
if (i < numOfCols && (pCol->columnIndex > columnIndex || pCol->tableUid != uid)) {
SColumn* b = calloc(1, sizeof(SColumn));
if (b == NULL) {
return NULL;
}
b->columnIndex = columnIndex;
b->tableUid = uid;
b->uid = uid;
b->flag = flag;
b->info.colId = pSchema->colId;
b->info.bytes = pSchema->bytes;
b->info.type = pSchema->type;
tstrncpy(b->name, pSchema->name, tListLen(b->name));
taosArrayInsert(pColumnList, i, &b);
}
}
return taosArrayGetP(pColumnList, i);
return b;
}
SColumn* insertPrimaryTsColumn(SArray* pColumnList, uint64_t tableUid) {
SSchema s = {.type = TSDB_DATA_TYPE_TIMESTAMP, .bytes = TSDB_KEYSIZE, .colId = PRIMARYKEY_TIMESTAMP_COL_ID};
return columnListInsert(pColumnList, PRIMARYKEY_TIMESTAMP_COL_ID, tableUid, &s);
return columnListInsert(pColumnList, tableUid, &s, TSDB_COL_NORMAL);
}
void columnCopy(SColumn* pDest, const SColumn* pSrc);
......@@ -817,8 +827,7 @@ SColumnFilterInfo* tFilterInfoDup(const SColumnFilterInfo* src, int32_t numOfFil
void columnCopy(SColumn* pDest, const SColumn* pSrc) {
destroyFilterInfo(&pDest->info.flist);
pDest->columnIndex = pSrc->columnIndex;
pDest->tableUid = pSrc->tableUid;
pDest->uid = pSrc->uid;
pDest->info.flist.numOfFilters = pSrc->info.flist.numOfFilters;
pDest->info.flist.filterInfo = tFilterInfoDup(pSrc->info.flist.filterInfo, pSrc->info.flist.numOfFilters);
pDest->info.type = pSrc->info.type;
......@@ -844,7 +853,7 @@ void columnListCopy(SArray* dst, const SArray* src, uint64_t uid) {
for (int32_t i = 0; i < num; ++i) {
SColumn* pCol = taosArrayGetP(src, i);
if (pCol->tableUid == uid) {
if (pCol->uid == uid) {
SColumn* p = columnClone(pCol);
taosArrayPush(dst, &p);
}
......
......@@ -55,7 +55,7 @@ SSchema* getTableTagSchema(const STableMeta* pTableMeta) {
return getOneColumnSchema(pTableMeta, getTableInfo(pTableMeta).numOfColumns);
}
static tExprNode* createUnaryFunctionExprNode(int32_t functionId, SSchema* pSchema, tExprNode* pColumnNode) {
static tExprNode* createFunctionExprNode(int32_t functionId, SSchema* pSchema, tExprNode* pColumnNode, int32_t numOfCols) {
if (pColumnNode == NULL) {
pColumnNode = calloc(1, sizeof(tExprNode));
pColumnNode->nodeType = TEXPR_COL_NODE;
......@@ -66,9 +66,10 @@ static tExprNode* createUnaryFunctionExprNode(int32_t functionId, SSchema* pSche
}
tExprNode* pNode = calloc(1, sizeof(tExprNode));
pNode->nodeType = TEXPR_UNARYEXPR_NODE;
pNode->_node.functionId = functionId;
pNode->_node.pLeft = pColumnNode;
pNode->nodeType = TEXPR_FUNCTION_NODE;
pNode->_function.functionId = functionId;
pNode->_function.pChild = pColumnNode;
pNode->_function.num = numOfCols;
return pNode;
}
......@@ -92,48 +93,50 @@ SExprInfo* createExprInfo(STableMetaInfo* pTableMetaInfo, int16_t functionId, SC
return NULL;
}
uint64_t uid = 0;
if (pTableMetaInfo->pTableMeta) {
uid = pTableMetaInfo->pTableMeta->uid;
}
SSqlExpr* p = &pExpr->base;
p->pColumns = calloc(1, sizeof(SColumn));
p->numOfCols = 1;
if (pParamExpr != NULL) {
pExpr->pExpr = createUnaryFunctionExprNode(functionId, NULL, pParamExpr);
pExpr->pExpr = createFunctionExprNode(functionId, NULL, pParamExpr, 1);
// pExpr->base.pColumns
// todo set the correct number of columns
} else if (pColIndex->columnIndex == TSDB_TBNAME_COLUMN_INDEX) {
assert(pParamExpr == NULL);
SSchema* s = getTbnameColumnSchema();
p->colInfo.colId = TSDB_TBNAME_COLUMN_INDEX;
pExpr->pExpr = createUnaryFunctionExprNode(functionId, s, pParamExpr);
setColumn(p->pColumns, uid, pTableMetaInfo->aliasName, TSDB_COL_TAG, s);
pExpr->pExpr = createFunctionExprNode(functionId, s, pParamExpr, 1);
} else if (pColIndex->columnIndex <= TSDB_UD_COLUMN_INDEX || functionId == FUNCTION_BLKINFO) {
assert(pParamExpr == NULL);
setColumn(p->pColumns, uid, pTableMetaInfo->aliasName, TSDB_COL_UDC, pResSchema);
p->colInfo.colId = pColIndex->columnIndex;
SSchema s = createSchema(pResSchema->type, pResSchema->bytes, pColIndex->columnIndex, pResSchema->name);
pExpr->pExpr = createUnaryFunctionExprNode(functionId, &s, pParamExpr);
pExpr->pExpr = createFunctionExprNode(functionId, &s, pParamExpr, 1);
} else {
int32_t len = tListLen(p->colInfo.name);
if (TSDB_COL_IS_TAG(pColIndex->type)) {
SSchema* pSchema = getTableTagSchema(pTableMetaInfo->pTableMeta);
p->colInfo.colId = pSchema[pColIndex->columnIndex].colId;
pExpr->pExpr = createUnaryFunctionExprNode(functionId, &pSchema[pColIndex->columnIndex], pParamExpr);
snprintf(p->colInfo.name, len, "%s.%s", pTableMetaInfo->aliasName, pSchema[pColIndex->columnIndex].name);
setColumn(p->pColumns, uid, pTableMetaInfo->aliasName, TSDB_COL_TAG, &pSchema[pColIndex->columnIndex]);
pExpr->pExpr = createFunctionExprNode(functionId, &pSchema[pColIndex->columnIndex], pParamExpr, 1);
} else if (pTableMetaInfo->pTableMeta != NULL) {
// in handling select database/version/server_status(), the pTableMeta is NULL
SSchema* pSchema = getOneColumnSchema(pTableMetaInfo->pTableMeta, pColIndex->columnIndex);
p->colInfo.colId = pSchema->colId;
snprintf(p->colInfo.name, len, "%s.%s", pTableMetaInfo->aliasName, pSchema->name);
setColumn(p->pColumns, uid, pTableMetaInfo->aliasName, TSDB_COL_NORMAL, pSchema);
pExpr->pExpr = createUnaryFunctionExprNode(functionId, pSchema, pParamExpr);
pExpr->pExpr = createFunctionExprNode(functionId, pSchema, pParamExpr, 1);
}
}
p->colInfo.flag = pColIndex->type;
p->colInfo.colIndex = pColIndex->columnIndex;
p->pColumns->flag = pColIndex->type;
p->interBytes = interSize;
memcpy(&p->resSchema, pResSchema, sizeof(SSchema));
if (pTableMetaInfo->pTableMeta) {
p->uid = pTableMetaInfo->pTableMeta->uid;
}
return pExpr;
}
......@@ -152,10 +155,9 @@ void updateExprInfo(SExprInfo* pExprInfo, int16_t functionId, int32_t colId, int
assert(pExprInfo != NULL);
SSqlExpr* pse = &pExprInfo->base;
pExprInfo->pExpr->_node.functionId = functionId;
pExprInfo->pExpr->_function.functionId = functionId;
assert(0);
pse->colInfo.colIndex = srcColumnIndex;
pse->colInfo.colId = colId;
pse->resSchema.type = resType;
pse->resSchema.bytes = resSize;
}
......@@ -198,7 +200,7 @@ void addExprInfoParam(SSqlExpr* pExpr, char* argument, int32_t type, int32_t byt
int32_t getExprFunctionId(SExprInfo *pExprInfo) {
assert(pExprInfo != NULL && pExprInfo->pExpr != NULL && pExprInfo->pExpr->nodeType == TEXPR_UNARYEXPR_NODE);
return pExprInfo->pExpr->_node.functionId;
return pExprInfo->pExpr->_function.functionId;
}
void assignExprInfo(SExprInfo* dst, const SExprInfo* src) {
......@@ -225,8 +227,9 @@ int32_t copyExprInfoList(SArray* dst, const SArray* src, uint64_t uid, bool deep
size_t size = taosArrayGetSize(src);
for (int32_t i = 0; i < size; ++i) {
SExprInfo* pExpr = taosArrayGetP(src, i);
uint64_t exprUid = pExpr->base.pColumns->uid;
if (pExpr->base.uid == uid) {
if (exprUid == uid) {
if (deepcopy) {
SExprInfo* p1 = calloc(1, sizeof(SExprInfo));
assignExprInfo(p1, pExpr);
......@@ -300,7 +303,7 @@ SArray* extractFunctionIdList(SArray* pExprInfoList) {
SArray* p = taosArrayInit(len, sizeof(int32_t));
for(int32_t i = 0; i < len; ++i) {
SExprInfo* pExprInfo = taosArrayGetP(pExprInfoList, i);
taosArrayPush(p, &pExprInfo->pExpr->_node.functionId);
taosArrayPush(p, &pExprInfo->pExpr->_function.functionId);
}
return p;
......
......@@ -50,7 +50,7 @@ void setTableMetaInfo(SQueryStmtInfo* pQueryInfo, SMetaReq *req) {
strcpy(pTableMetaInfo->aliasName, name->tname);
STableMeta* pTableMeta = pTableMetaInfo->pTableMeta;
pTableMeta->tableType = TSDB_NORMAL_TABLE;
pTableMeta->tableInfo.numOfColumns = 4;
pTableMeta->tableInfo.numOfColumns = 6;
pTableMeta->tableInfo.rowSize = 28;
pTableMeta->uid = 110;
......@@ -61,116 +61,12 @@ 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);
}
}
TEST(testCase, validateAST_test) {
SSqlInfo info1 = doGenerateAST("select a a1111, a+b + 22, tbname from `t.1abc` where ts<now+2h and `col` < 20 + 99");
ASSERT_EQ(info1.valid, true);
char msg[128] = {0};
SMsgBuf buf;
buf.len = 128;
buf.buf = msg;
SSqlNode* pNode = (SSqlNode*) taosArrayGetP(((SArray*)info1.list), 0);
int32_t code = evaluateSqlNode(pNode, TSDB_TIME_PRECISION_NANO, &buf);
ASSERT_EQ(code, 0);
SMetaReq req = {0};
int32_t ret = qParserExtractRequestedMetaInfo(&info1, &req, msg, 128);
ASSERT_EQ(ret, 0);
ASSERT_EQ(taosArrayGetSize(req.pTableName), 1);
SQueryStmtInfo* pQueryInfo = createQueryInfo();
setTableMetaInfo(pQueryInfo, &req);
SSqlNode* pSqlNode = (SSqlNode*)taosArrayGetP(info1.list, 0);
ret = validateSqlNode(pSqlNode, pQueryInfo, &buf);
SArray* pExprList = pQueryInfo->exprList;
ASSERT_EQ(taosArrayGetSize(pExprList), 3);
SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 0);
ASSERT_EQ(p1->base.uid, 110);
ASSERT_EQ(p1->base.numOfParams, 0);
ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_INT);
ASSERT_STRCASEEQ(p1->base.resSchema.name, "a1111");
ASSERT_STRCASEEQ(p1->base.colInfo.name, "t.1abc.a");
ASSERT_EQ(p1->base.colInfo.colId, 1);
ASSERT_EQ(p1->base.colInfo.flag, TSDB_COL_NORMAL);
ASSERT_STRCASEEQ(p1->base.token, "a");
ASSERT_EQ(taosArrayGetSize(pExprList), 3);
SExprInfo* p2 = (SExprInfo*) taosArrayGetP(pExprList, 1);
ASSERT_EQ(p2->base.uid, 0);
ASSERT_EQ(p2->base.numOfParams, 1); // it is the serialized binary string of expression.
ASSERT_EQ(p2->base.resSchema.type, TSDB_DATA_TYPE_DOUBLE);
ASSERT_STRCASEEQ(p2->base.resSchema.name, "a+b + 22");
// ASSERT_STRCASEEQ(p2->base.colInfo.name, "t.1abc.a");
// ASSERT_EQ(p1->base.colInfo.colId, 1);
// ASSERT_EQ(p1->base.colInfo.flag, TSDB_COL_NORMAL);
ASSERT_STRCASEEQ(p2->base.token, "a+b + 22");
ASSERT_EQ(taosArrayGetSize(pQueryInfo->colList), 3);
ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 3);
destroyQueryInfo(pQueryInfo);
qParserClearupMetaRequestInfo(&req);
destroySqlInfo(&info1);
}
TEST(testCase, function_Test) {
SSqlInfo info1 = doGenerateAST("select count(a) from `t.1abc`");
ASSERT_EQ(info1.valid, true);
char msg[128] = {0};
SMsgBuf buf;
buf.len = 128;
buf.buf = msg;
SSqlNode* pNode = (SSqlNode*) taosArrayGetP(((SArray*)info1.list), 0);
int32_t code = evaluateSqlNode(pNode, TSDB_TIME_PRECISION_NANO, &buf);
ASSERT_EQ(code, 0);
SMetaReq req = {0};
int32_t ret = qParserExtractRequestedMetaInfo(&info1, &req, msg, 128);
ASSERT_EQ(ret, 0);
ASSERT_EQ(taosArrayGetSize(req.pTableName), 1);
SQueryStmtInfo* pQueryInfo = createQueryInfo();
setTableMetaInfo(pQueryInfo, &req);
SSqlNode* pSqlNode = (SSqlNode*)taosArrayGetP(info1.list, 0);
ret = validateSqlNode(pSqlNode, pQueryInfo, &buf);
SArray* pExprList = pQueryInfo->exprList;
ASSERT_EQ(taosArrayGetSize(pExprList), 1);
SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 0);
ASSERT_EQ(p1->base.uid, 110);
ASSERT_EQ(p1->base.numOfParams, 0);
ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_BIGINT);
ASSERT_STRCASEEQ(p1->base.resSchema.name, "count(a)");
ASSERT_STRCASEEQ(p1->base.colInfo.name, "t.1abc.a");
ASSERT_EQ(p1->base.colInfo.colId, 1);
ASSERT_EQ(p1->base.colInfo.flag, TSDB_COL_NORMAL);
ASSERT_STRCASEEQ(p1->base.token, "count(a)");
ASSERT_EQ(p1->base.interBytes, 8);
ASSERT_EQ(taosArrayGetSize(pQueryInfo->colList), 2);
ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 1);
destroyQueryInfo(pQueryInfo);
qParserClearupMetaRequestInfo(&req);
destroySqlInfo(&info1);
setSchema(&pSchema[4], TSDB_DATA_TYPE_BINARY, 12, "c", 4);
setSchema(&pSchema[5], TSDB_DATA_TYPE_BINARY, 44, "d", 5);
}
TEST(testCase, function_Test2) {
SSqlInfo info1 = doGenerateAST("select count(a) abc from `t.1abc`");
void sqlCheck(const char* sql, bool valid) {
SSqlInfo info1 = doGenerateAST(sql);
ASSERT_EQ(info1.valid, true);
char msg[128] = {0};
......@@ -193,164 +89,314 @@ TEST(testCase, function_Test2) {
SSqlNode* pSqlNode = (SSqlNode*)taosArrayGetP(info1.list, 0);
ret = validateSqlNode(pSqlNode, pQueryInfo, &buf);
SArray* pExprList = pQueryInfo->exprList;
ASSERT_EQ(taosArrayGetSize(pExprList), 1);
SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 0);
ASSERT_EQ(p1->base.uid, 110);
ASSERT_EQ(p1->base.numOfParams, 0);
ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_BIGINT);
ASSERT_STRCASEEQ(p1->base.resSchema.name, "abc");
ASSERT_STRCASEEQ(p1->base.colInfo.name, "t.1abc.a");
ASSERT_EQ(p1->base.colInfo.colId, 1);
ASSERT_EQ(p1->base.colInfo.flag, TSDB_COL_NORMAL);
ASSERT_STRCASEEQ(p1->base.token, "count(a)");
ASSERT_EQ(p1->base.interBytes, 8);
ASSERT_EQ(taosArrayGetSize(pQueryInfo->colList), 2);
ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 1);
destroyQueryInfo(pQueryInfo);
qParserClearupMetaRequestInfo(&req);
destroySqlInfo(&info1);
}
TEST(testCase, function_Test3) {
SSqlInfo info1 = doGenerateAST("select first(*) from `t.1abc`");
ASSERT_EQ(info1.valid, true);
char msg[128] = {0};
SMsgBuf buf;
buf.len = 128;
buf.buf = msg;
SSqlNode* pNode = (SSqlNode*) taosArrayGetP(((SArray*)info1.list), 0);
int32_t code = evaluateSqlNode(pNode, TSDB_TIME_PRECISION_NANO, &buf);
ASSERT_EQ(code, 0);
SMetaReq req = {0};
int32_t ret = qParserExtractRequestedMetaInfo(&info1, &req, msg, 128);
if (valid) {
ASSERT_EQ(ret, 0);
ASSERT_EQ(taosArrayGetSize(req.pTableName), 1);
SQueryStmtInfo* pQueryInfo = createQueryInfo();
setTableMetaInfo(pQueryInfo, &req);
SSqlNode* pSqlNode = (SSqlNode*)taosArrayGetP(info1.list, 0);
ret = validateSqlNode(pSqlNode, pQueryInfo, &buf);
SArray* pExprList = pQueryInfo->exprList;
ASSERT_EQ(taosArrayGetSize(pExprList), 4);
SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 0);
ASSERT_EQ(p1->base.uid, 110);
ASSERT_EQ(p1->base.numOfParams, 0);
ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_TIMESTAMP);
ASSERT_STRCASEEQ(p1->base.resSchema.name, "first(ts)");
ASSERT_STRCASEEQ(p1->base.colInfo.name, "t.1abc.ts");
ASSERT_EQ(p1->base.colInfo.colId, 0);
ASSERT_EQ(p1->base.colInfo.flag, TSDB_COL_NORMAL);
ASSERT_STRCASEEQ(p1->base.token, "first(ts)");
ASSERT_EQ(p1->base.interBytes, 24);
ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 4);
} else {
ASSERT_NE(ret, 0);
}
destroyQueryInfo(pQueryInfo);
qParserClearupMetaRequestInfo(&req);
destroySqlInfo(&info1);
}
TEST(testCase, function_Test4) {
SSqlInfo info1 = doGenerateAST("select _block_dist() as a1 from `t.1abc`");
ASSERT_EQ(info1.valid, true);
char msg[128] = {0};
SMsgBuf buf;
buf.len = 128;
buf.buf = msg;
SSqlNode* pNode = (SSqlNode*) taosArrayGetP(((SArray*)info1.list), 0);
int32_t code = evaluateSqlNode(pNode, TSDB_TIME_PRECISION_NANO, &buf);
ASSERT_EQ(code, 0);
SMetaReq req = {0};
int32_t ret = qParserExtractRequestedMetaInfo(&info1, &req, msg, 128);
ASSERT_EQ(ret, 0);
ASSERT_EQ(taosArrayGetSize(req.pTableName), 1);
SQueryStmtInfo* pQueryInfo = createQueryInfo();
setTableMetaInfo(pQueryInfo, &req);
SSqlNode* pSqlNode = (SSqlNode*)taosArrayGetP(info1.list, 0);
ret = validateSqlNode(pSqlNode, pQueryInfo, &buf);
SArray* pExprList = pQueryInfo->exprList;
ASSERT_EQ(taosArrayGetSize(pExprList), 1);
SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 0);
ASSERT_EQ(p1->base.uid, 110);
ASSERT_EQ(p1->base.numOfParams, 1);
ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_BINARY);
ASSERT_STRCASEEQ(p1->base.resSchema.name, "a1");
// ASSERT_STRCASEEQ(p1->base.colInfo.name, "t.1abc.ts");
// ASSERT_EQ(p1->base.colInfo.colId, 0);
ASSERT_EQ(p1->base.colInfo.flag, TSDB_COL_NORMAL);
ASSERT_STRCASEEQ(p1->base.token, "_block_dist()");
ASSERT_EQ(p1->base.interBytes, 0);
ASSERT_EQ(taosArrayGetSize(pQueryInfo->colList), 1);
ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 1);
destroyQueryInfo(pQueryInfo);
qParserClearupMetaRequestInfo(&req);
destroySqlInfo(&info1);
}
TEST(testCase, function_Test5) {
SSqlInfo info1 = doGenerateAST("select sum(a) + avg(b) as a1 from `t.1abc`");
ASSERT_EQ(info1.valid, true);
char msg[128] = {0};
SMsgBuf buf;
buf.len = 128;
buf.buf = msg;
SSqlNode* pNode = (SSqlNode*) taosArrayGetP(((SArray*)info1.list), 0);
int32_t code = evaluateSqlNode(pNode, TSDB_TIME_PRECISION_NANO, &buf);
ASSERT_EQ(code, 0);
SMetaReq req = {0};
int32_t ret = qParserExtractRequestedMetaInfo(&info1, &req, msg, 128);
ASSERT_EQ(ret, 0);
ASSERT_EQ(taosArrayGetSize(req.pTableName), 1);
SQueryStmtInfo* pQueryInfo = createQueryInfo();
setTableMetaInfo(pQueryInfo, &req);
SSqlNode* pSqlNode = (SSqlNode*)taosArrayGetP(info1.list, 0);
ret = validateSqlNode(pSqlNode, pQueryInfo, &buf);
ASSERT_EQ(ret, 0);
SArray* pExprList = pQueryInfo->exprList;
ASSERT_EQ(taosArrayGetSize(pExprList), 3);
SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 0);
ASSERT_EQ(p1->base.uid, 0);
ASSERT_EQ(p1->base.numOfParams, 1);
ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_DOUBLE);
ASSERT_STRCASEEQ(p1->base.resSchema.name, "a1");
// ASSERT_STRCASEEQ(p1->base.colInfo.name, "t.1abc.ts");
// ASSERT_EQ(p1->base.colInfo.colId, 0);
ASSERT_EQ(p1->base.colInfo.flag, TSDB_COL_NORMAL);
ASSERT_STRCASEEQ(p1->base.token, "sum(a) + avg(b)");
ASSERT_EQ(p1->base.interBytes, 0);
ASSERT_EQ(taosArrayGetSize(pQueryInfo->colList), 3);
ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 1);
destroyQueryInfo(pQueryInfo);
qParserClearupMetaRequestInfo(&req);
destroySqlInfo(&info1);
//TEST(testCase, validateAST_test) {
// SSqlInfo info1 = doGenerateAST("select a a1111, a+b + 22, tbname from `t.1abc` where ts<now+2h and `col` < 20 + 99");
// ASSERT_EQ(info1.valid, true);
//
// char msg[128] = {0};
// SMsgBuf buf;
// buf.len = 128;
// buf.buf = msg;
//
// SSqlNode* pNode = (SSqlNode*) taosArrayGetP(((SArray*)info1.list), 0);
// int32_t code = evaluateSqlNode(pNode, TSDB_TIME_PRECISION_NANO, &buf);
// ASSERT_EQ(code, 0);
//
// SMetaReq req = {0};
// int32_t ret = qParserExtractRequestedMetaInfo(&info1, &req, msg, 128);
// ASSERT_EQ(ret, 0);
// ASSERT_EQ(taosArrayGetSize(req.pTableName), 1);
//
// SQueryStmtInfo* pQueryInfo = createQueryInfo();
// setTableMetaInfo(pQueryInfo, &req);
//
// SSqlNode* pSqlNode = (SSqlNode*)taosArrayGetP(info1.list, 0);
// ret = validateSqlNode(pSqlNode, pQueryInfo, &buf);
//
// SArray* pExprList = pQueryInfo->exprList;
// ASSERT_EQ(taosArrayGetSize(pExprList), 3);
//
// SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 0);
// ASSERT_EQ(p1->base.pColumns->info.colId, 110);
// ASSERT_EQ(p1->base.numOfParams, 0);
// ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_INT);
// ASSERT_STRCASEEQ(p1->base.resSchema.name, "a1111");
// ASSERT_STRCASEEQ(p1->base.pColumns->name, "t.1abc.a");
// ASSERT_EQ(p1->base.pColumns->info.colId, 1);
// ASSERT_EQ(p1->base.pColumns->flag, TSDB_COL_NORMAL);
// ASSERT_STRCASEEQ(p1->base.token, "a");
//
// ASSERT_EQ(taosArrayGetSize(pExprList), 3);
//
// SExprInfo* p2 = (SExprInfo*) taosArrayGetP(pExprList, 1);
// ASSERT_EQ(p2->base.pColumns->uid, 0);
// ASSERT_EQ(p2->base.numOfParams, 1); // it is the serialized binary string of expression.
// ASSERT_EQ(p2->base.resSchema.type, TSDB_DATA_TYPE_DOUBLE);
// ASSERT_STRCASEEQ(p2->base.resSchema.name, "a+b + 22");
//
//// ASSERT_STRCASEEQ(p2->base.colInfo.name, "t.1abc.a");
//// ASSERT_EQ(p1->base.colInfo.colId, 1);
//// ASSERT_EQ(p1->base.colInfo.flag, TSDB_COL_NORMAL);
// ASSERT_STRCASEEQ(p2->base.token, "a+b + 22");
//
// ASSERT_EQ(taosArrayGetSize(pQueryInfo->colList), 3);
// ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 3);
//
// destroyQueryInfo(pQueryInfo);
// qParserClearupMetaRequestInfo(&req);
// destroySqlInfo(&info1);
//}
//
//TEST(testCase, function_Test) {
// SSqlInfo info1 = doGenerateAST("select count(a) from `t.1abc`");
// ASSERT_EQ(info1.valid, true);
//
// char msg[128] = {0};
// SMsgBuf buf;
// buf.len = 128;
// buf.buf = msg;
//
// SSqlNode* pNode = (SSqlNode*) taosArrayGetP(((SArray*)info1.list), 0);
// int32_t code = evaluateSqlNode(pNode, TSDB_TIME_PRECISION_NANO, &buf);
// ASSERT_EQ(code, 0);
//
// SMetaReq req = {0};
// int32_t ret = qParserExtractRequestedMetaInfo(&info1, &req, msg, 128);
// ASSERT_EQ(ret, 0);
// ASSERT_EQ(taosArrayGetSize(req.pTableName), 1);
//
// SQueryStmtInfo* pQueryInfo = createQueryInfo();
// setTableMetaInfo(pQueryInfo, &req);
//
// SSqlNode* pSqlNode = (SSqlNode*)taosArrayGetP(info1.list, 0);
// ret = validateSqlNode(pSqlNode, pQueryInfo, &buf);
//
// SArray* pExprList = pQueryInfo->exprList;
// ASSERT_EQ(taosArrayGetSize(pExprList), 1);
//
// SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 0);
// ASSERT_EQ(p1->base.pColumns->uid, 110);
// ASSERT_EQ(p1->base.numOfParams, 0);
// ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_BIGINT);
// ASSERT_STRCASEEQ(p1->base.resSchema.name, "count(a)");
// ASSERT_STRCASEEQ(p1->base.pColumns->name, "t.1abc.a");
// ASSERT_EQ(p1->base.pColumns->info.colId, 1);
// ASSERT_EQ(p1->base.pColumns->flag, TSDB_COL_NORMAL);
// ASSERT_STRCASEEQ(p1->base.token, "count(a)");
// ASSERT_EQ(p1->base.interBytes, 8);
//
// ASSERT_EQ(taosArrayGetSize(pQueryInfo->colList), 2);
// ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 1);
//
// destroyQueryInfo(pQueryInfo);
// qParserClearupMetaRequestInfo(&req);
// destroySqlInfo(&info1);
//}
//
//TEST(testCase, function_Test2) {
// SSqlInfo info1 = doGenerateAST("select count(a) abc from `t.1abc`");
// ASSERT_EQ(info1.valid, true);
//
// char msg[128] = {0};
// SMsgBuf buf;
// buf.len = 128;
// buf.buf = msg;
//
// SSqlNode* pNode = (SSqlNode*) taosArrayGetP(((SArray*)info1.list), 0);
// int32_t code = evaluateSqlNode(pNode, TSDB_TIME_PRECISION_NANO, &buf);
// ASSERT_EQ(code, 0);
//
// SMetaReq req = {0};
// int32_t ret = qParserExtractRequestedMetaInfo(&info1, &req, msg, 128);
// ASSERT_EQ(ret, 0);
// ASSERT_EQ(taosArrayGetSize(req.pTableName), 1);
//
// SQueryStmtInfo* pQueryInfo = createQueryInfo();
// setTableMetaInfo(pQueryInfo, &req);
//
// SSqlNode* pSqlNode = (SSqlNode*)taosArrayGetP(info1.list, 0);
// ret = validateSqlNode(pSqlNode, pQueryInfo, &buf);
//
// SArray* pExprList = pQueryInfo->exprList;
// ASSERT_EQ(taosArrayGetSize(pExprList), 1);
//
// SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 0);
// ASSERT_EQ(p1->base.pColumns->uid, 110);
// ASSERT_EQ(p1->base.numOfParams, 0);
// ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_BIGINT);
// ASSERT_STRCASEEQ(p1->base.resSchema.name, "abc");
// ASSERT_STRCASEEQ(p1->base.pColumns->name, "t.1abc.a");
// ASSERT_EQ(p1->base.pColumns->info.colId, 1);
// ASSERT_EQ(p1->base.pColumns->flag, TSDB_COL_NORMAL);
// ASSERT_STRCASEEQ(p1->base.token, "count(a)");
// ASSERT_EQ(p1->base.interBytes, 8);
//
// ASSERT_EQ(taosArrayGetSize(pQueryInfo->colList), 2);
// ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 1);
//
// destroyQueryInfo(pQueryInfo);
// qParserClearupMetaRequestInfo(&req);
// destroySqlInfo(&info1);
//}
//
//TEST(testCase, function_Test3) {
// SSqlInfo info1 = doGenerateAST("select first(*) from `t.1abc`");
// ASSERT_EQ(info1.valid, true);
//
// char msg[128] = {0};
// SMsgBuf buf;
// buf.len = 128;
// buf.buf = msg;
//
// SSqlNode* pNode = (SSqlNode*) taosArrayGetP(((SArray*)info1.list), 0);
// int32_t code = evaluateSqlNode(pNode, TSDB_TIME_PRECISION_NANO, &buf);
// ASSERT_EQ(code, 0);
//
// SMetaReq req = {0};
// int32_t ret = qParserExtractRequestedMetaInfo(&info1, &req, msg, 128);
// ASSERT_EQ(ret, 0);
// ASSERT_EQ(taosArrayGetSize(req.pTableName), 1);
//
// SQueryStmtInfo* pQueryInfo = createQueryInfo();
// setTableMetaInfo(pQueryInfo, &req);
//
// SSqlNode* pSqlNode = (SSqlNode*)taosArrayGetP(info1.list, 0);
// ret = validateSqlNode(pSqlNode, pQueryInfo, &buf);
//
// SArray* pExprList = pQueryInfo->exprList;
// ASSERT_EQ(taosArrayGetSize(pExprList), 4);
//
// SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 0);
// ASSERT_EQ(p1->base.pColumns->uid, 110);
// ASSERT_EQ(p1->base.numOfParams, 0);
// ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_TIMESTAMP);
// ASSERT_STRCASEEQ(p1->base.resSchema.name, "first(ts)");
// ASSERT_STRCASEEQ(p1->base.pColumns->name, "t.1abc.ts");
// ASSERT_EQ(p1->base.pColumns->info.colId, 0);
// ASSERT_EQ(p1->base.pColumns->flag, TSDB_COL_NORMAL);
// ASSERT_STRCASEEQ(p1->base.token, "first(ts)");
// ASSERT_EQ(p1->base.interBytes, 24);
//
// ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 4);
//
// destroyQueryInfo(pQueryInfo);
// qParserClearupMetaRequestInfo(&req);
// destroySqlInfo(&info1);
//}
//
//TEST(testCase, function_Test4) {
// SSqlInfo info1 = doGenerateAST("select _block_dist() as a1 from `t.1abc`");
// ASSERT_EQ(info1.valid, true);
//
// char msg[128] = {0};
// SMsgBuf buf;
// buf.len = 128;
// buf.buf = msg;
//
// SSqlNode* pNode = (SSqlNode*) taosArrayGetP(((SArray*)info1.list), 0);
// int32_t code = evaluateSqlNode(pNode, TSDB_TIME_PRECISION_NANO, &buf);
// ASSERT_EQ(code, 0);
//
// SMetaReq req = {0};
// int32_t ret = qParserExtractRequestedMetaInfo(&info1, &req, msg, 128);
// ASSERT_EQ(ret, 0);
// ASSERT_EQ(taosArrayGetSize(req.pTableName), 1);
//
// SQueryStmtInfo* pQueryInfo = createQueryInfo();
// setTableMetaInfo(pQueryInfo, &req);
//
// SSqlNode* pSqlNode = (SSqlNode*)taosArrayGetP(info1.list, 0);
// ret = validateSqlNode(pSqlNode, pQueryInfo, &buf);
//
// SArray* pExprList = pQueryInfo->exprList;
// ASSERT_EQ(taosArrayGetSize(pExprList), 1);
//
// SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 0);
// ASSERT_EQ(p1->base.pColumns->uid, 110);
// ASSERT_EQ(p1->base.numOfParams, 1);
// ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_BINARY);
// ASSERT_STRCASEEQ(p1->base.resSchema.name, "a1");
//// ASSERT_STRCASEEQ(p1->base.colInfo.name, "t.1abc.ts");
//// ASSERT_EQ(p1->base.colInfo.colId, 0);
// ASSERT_EQ(p1->base.pColumns->flag, TSDB_COL_NORMAL);
// ASSERT_STRCASEEQ(p1->base.token, "_block_dist()");
// ASSERT_EQ(p1->base.interBytes, 0);
//
// ASSERT_EQ(taosArrayGetSize(pQueryInfo->colList), 1);
// ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 1);
//
// destroyQueryInfo(pQueryInfo);
// qParserClearupMetaRequestInfo(&req);
// destroySqlInfo(&info1);
//}
//TEST(testCase, function_Test5) {
// //todo select concat(concat(a, b), concat(b, a)) from `t.1abc`;
//
// SSqlInfo info1 = doGenerateAST("select sum(a) + avg(b) as a1 from `t.1abc`");
// ASSERT_EQ(info1.valid, true);
//
// char msg[128] = {0};
// SMsgBuf buf;
// buf.len = 128;
// buf.buf = msg;
//
// SSqlNode* pNode = (SSqlNode*) taosArrayGetP(((SArray*)info1.list), 0);
// int32_t code = evaluateSqlNode(pNode, TSDB_TIME_PRECISION_NANO, &buf);
// ASSERT_EQ(code, 0);
//
// SMetaReq req = {0};
// int32_t ret = qParserExtractRequestedMetaInfo(&info1, &req, msg, 128);
// ASSERT_EQ(ret, 0);
// ASSERT_EQ(taosArrayGetSize(req.pTableName), 1);
//
// SQueryStmtInfo* pQueryInfo = createQueryInfo();
// setTableMetaInfo(pQueryInfo, &req);
//
// SSqlNode* pSqlNode = (SSqlNode*)taosArrayGetP(info1.list, 0);
// ret = validateSqlNode(pSqlNode, pQueryInfo, &buf);
// ASSERT_EQ(ret, 0);
//
// SArray* pExprList = pQueryInfo->exprList;
// ASSERT_EQ(taosArrayGetSize(pExprList), 3);
//
// SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 0);
// ASSERT_EQ(p1->base.numOfCols, 2);
// ASSERT_EQ(p1->base.pColumns->uid, 110);
//
// ASSERT_EQ(p1->base.numOfParams, 1);
// ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_DOUBLE);
// ASSERT_STRCASEEQ(p1->base.resSchema.name, "a1");
//
// ASSERT_EQ(p1->base.pColumns->flag, TSDB_COL_NORMAL);
// ASSERT_STRCASEEQ(p1->base.token, "sum(a) + avg(b)");
// ASSERT_EQ(p1->base.interBytes, 0);
//
// ASSERT_EQ(taosArrayGetSize(pQueryInfo->colList), 3);
// ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 1);
//
// destroyQueryInfo(pQueryInfo);
// qParserClearupMetaRequestInfo(&req);
// destroySqlInfo(&info1);
//}
TEST(testCase, function_Test10) {
// sqlCheck("select c from `t.1abc`", true);
// sqlCheck("select length(c) from `t.1abc`", true);
sqlCheck("select sum(length(a+b)) from `t.1abc`", false);
// sqlCheck("select sum(sum(a+b)) from `t.1abc`", false);
}
TEST(testCase, function_Test6) {
......@@ -382,15 +428,15 @@ TEST(testCase, function_Test6) {
ASSERT_EQ(taosArrayGetSize(pExprList), 5);
SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 0);
ASSERT_EQ(p1->base.uid, 110);
ASSERT_EQ(p1->base.pColumns->uid, 110);
ASSERT_EQ(p1->base.numOfParams, 0);
ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_DOUBLE);
ASSERT_STRCASEEQ(p1->base.resSchema.name, "a1");
ASSERT_EQ(p1->base.colInfo.flag, TSDB_COL_NORMAL);
ASSERT_EQ(p1->base.pColumns->flag, TSDB_COL_NORMAL);
ASSERT_STRCASEEQ(p1->base.token, "sum(a+b)");
ASSERT_EQ(p1->base.interBytes, 16);
ASSERT_EQ(p1->pExpr->nodeType, TEXPR_UNARYEXPR_NODE);
ASSERT_EQ(p1->pExpr->_node.functionId, FUNCTION_SUM);
ASSERT_EQ(p1->pExpr->_function.functionId, FUNCTION_SUM);
ASSERT_TRUE(p1->pExpr->_node.pRight == NULL);
tExprNode* pParam = p1->pExpr->_node.pLeft;
......@@ -404,15 +450,15 @@ TEST(testCase, function_Test6) {
ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 5);
SExprInfo* p2 = (SExprInfo*) taosArrayGetP(pExprList, 1);
ASSERT_EQ(p2->base.uid, 110);
ASSERT_EQ(p2->base.pColumns->uid, 110);
ASSERT_EQ(p2->base.numOfParams, 0);
ASSERT_EQ(p2->base.resSchema.type, TSDB_DATA_TYPE_DOUBLE);
ASSERT_STRCASEEQ(p2->base.resSchema.name, "first(b*a)");
ASSERT_EQ(p2->base.colInfo.flag, TSDB_COL_NORMAL);
ASSERT_EQ(p2->base.pColumns->flag, TSDB_COL_NORMAL);
ASSERT_STRCASEEQ(p2->base.token, "first(b*a)");
ASSERT_EQ(p2->base.interBytes, 24);
ASSERT_EQ(p2->pExpr->nodeType, TEXPR_UNARYEXPR_NODE);
ASSERT_EQ(p2->pExpr->_node.functionId, FUNCTION_FIRST);
ASSERT_EQ(p2->pExpr->_function.functionId, FUNCTION_FIRST);
ASSERT_TRUE(p2->pExpr->_node.pRight == NULL);
destroyQueryInfo(pQueryInfo);
......@@ -449,15 +495,15 @@ TEST(testCase, function_Test7) {
ASSERT_EQ(taosArrayGetSize(pExprList), 2);
SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 0);
ASSERT_EQ(p1->base.uid, 110);
ASSERT_EQ(p1->base.pColumns->uid, 110);
ASSERT_EQ(p1->base.numOfParams, 0);
ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_BIGINT);
ASSERT_STRCASEEQ(p1->base.resSchema.name, "count(a+b)");
ASSERT_EQ(p1->base.colInfo.flag, TSDB_COL_NORMAL);
ASSERT_EQ(p1->base.pColumns->flag, TSDB_COL_NORMAL);
ASSERT_STRCASEEQ(p1->base.token, "count(a+b)");
ASSERT_EQ(p1->base.interBytes, 8);
ASSERT_EQ(p1->pExpr->nodeType, TEXPR_UNARYEXPR_NODE);
ASSERT_EQ(p1->pExpr->_node.functionId, FUNCTION_COUNT);
ASSERT_EQ(p1->pExpr->_function.functionId, FUNCTION_COUNT);
ASSERT_TRUE(p1->pExpr->_node.pRight == NULL);
tExprNode* pParam = p1->pExpr->_node.pLeft;
......@@ -504,16 +550,16 @@ TEST(testCase, function_Test8) {
ASSERT_EQ(taosArrayGetSize(pExprList), 2);
SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 1);
ASSERT_EQ(p1->base.uid, 110);
ASSERT_EQ(p1->base.pColumns->uid, 110);
ASSERT_EQ(p1->base.numOfParams, 1);
ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_DOUBLE);
ASSERT_STRCASEEQ(p1->base.resSchema.name, "top(a*b / 99, 20)");
ASSERT_EQ(p1->base.colInfo.flag, TSDB_COL_NORMAL);
ASSERT_EQ(p1->base.pColumns->flag, TSDB_COL_NORMAL);
ASSERT_STRCASEEQ(p1->base.token, "top(a*b / 99, 20)");
ASSERT_EQ(p1->base.interBytes, 16);
ASSERT_EQ(p1->pExpr->nodeType, TEXPR_UNARYEXPR_NODE);
ASSERT_EQ(p1->pExpr->_node.functionId, FUNCTION_TOP);
ASSERT_EQ(p1->pExpr->_function.functionId, FUNCTION_TOP);
ASSERT_TRUE(p1->pExpr->_node.pRight == NULL);
tExprNode* pParam = p1->pExpr->_node.pLeft;
......
......@@ -95,16 +95,16 @@ TEST(testCase, planner_test) {
ASSERT_EQ(taosArrayGetSize(pExprList), 2);
SExprInfo* p1 = (SExprInfo*) taosArrayGetP(pExprList, 1);
ASSERT_EQ(p1->base.uid, 110);
ASSERT_EQ(p1->base.pColumns->uid, 110);
ASSERT_EQ(p1->base.numOfParams, 1);
ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_DOUBLE);
ASSERT_STRCASEEQ(p1->base.resSchema.name, "top(a*b / 99, 20)");
ASSERT_EQ(p1->base.colInfo.flag, TSDB_COL_NORMAL);
ASSERT_EQ(p1->base.pColumns->flag, TSDB_COL_NORMAL);
ASSERT_STRCASEEQ(p1->base.token, "top(a*b / 99, 20)");
ASSERT_EQ(p1->base.interBytes, 16);
ASSERT_EQ(p1->pExpr->nodeType, TEXPR_UNARYEXPR_NODE);
ASSERT_EQ(p1->pExpr->_node.functionId, FUNCTION_TOP);
ASSERT_EQ(p1->pExpr->nodeType, TEXPR_FUNCTION_NODE);
ASSERT_EQ(p1->pExpr->_function.functionId, FUNCTION_TOP);
ASSERT_TRUE(p1->pExpr->_node.pRight == NULL);
tExprNode* pParam = p1->pExpr->_node.pLeft;
......
......@@ -186,7 +186,7 @@ static SQueryPlanNode* doAddTableColumnNode(SQueryStmtInfo* pQueryInfo, STableMe
for (int32_t i = 0; i < numOfCols; ++i) {
SColumn* pCol = taosArrayGetP(tableCols, i);
SColumnIndex index = {.tableIndex = 0, .columnIndex = pCol->columnIndex};
SColumnIndex index = {.tableIndex = 0, /*.columnIndex = pCol->columnIndex*/};
SSchema* pSchema = getOneColumnSchema(pTableMetaInfo->pTableMeta, i);
SSchema resultSchema = *pSchema;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册