diff --git a/include/common/tvariant.h b/include/common/tvariant.h index 13c8aff8e724907217fff0c5629c991610c8d2c3..7143d7b8fdc8214bd40134805168606e985f92f6 100644 --- a/include/common/tvariant.h +++ b/include/common/tvariant.h @@ -36,6 +36,8 @@ typedef struct SVariant { }; } SVariant; +int32_t toInteger(const char* z, int32_t n, int32_t base, int64_t* value, bool* issigned); + bool taosVariantIsValid(SVariant *pVar); void taosVariantCreate(SVariant *pVar, char* z, int32_t n, int32_t type); diff --git a/source/common/CMakeLists.txt b/source/common/CMakeLists.txt index d03231fcfbcbdd9fdedab59c0b7c82e8195d5936..1ff83b091d27d36d3ab86e35fafe95ec7240e55f 100644 --- a/source/common/CMakeLists.txt +++ b/source/common/CMakeLists.txt @@ -10,4 +10,6 @@ target_link_libraries( PUBLIC os PUBLIC util INTERFACE api -) \ No newline at end of file +) + +ADD_SUBDIRECTORY(test) diff --git a/source/common/src/sqlcmdstr.c b/source/common/src/tmsgtype.c similarity index 100% rename from source/common/src/sqlcmdstr.c rename to source/common/src/tmsgtype.c diff --git a/source/common/src/tvariant.c b/source/common/src/tvariant.c index 5dcad85718a0f659d8c5a6f863b431eede8c391e..a218353ae3c4a51a7c2a1827bb5ba8116f8f6264 100644 --- a/source/common/src/tvariant.c +++ b/source/common/src/tvariant.c @@ -15,8 +15,8 @@ #include "os.h" #include "taos.h" -#include "thash.h" #include "taosdef.h" +#include "thash.h" #include "ttime.h" #include "ttokendef.h" #include "ttypes.h" @@ -39,6 +39,42 @@ assert(0); \ } while (0) +int32_t toInteger(const char* z, int32_t n, int32_t base, int64_t* value, bool* isSigned) { + errno = 0; + char* endPtr = NULL; + + int32_t index = 0; + + bool specifiedSign = (z[0] == '+' || z[0] == '-'); + if (specifiedSign) { + *isSigned = true; + index = 1; + } + + uint64_t val = strtoull(&z[index], &endPtr, base); + if (errno == ERANGE || errno == EINVAL) { + errno = 0; + return -1; + } + + if (specifiedSign && val > INT64_MAX) { + return -1; + } + + if (endPtr - &z[index] != n - index) { + return -1; + } + + *isSigned = specifiedSign || (val <= INT64_MAX); + if (*isSigned) { + *value = (z[0] == '-')? -val:val; + } else { + *(uint64_t*) value = val; + } + + return 0; +} + void taosVariantCreate(SVariant *pVar, char* z, int32_t n, int32_t type) { int32_t ret = 0; memset(pVar, 0, sizeof(SVariant)); @@ -52,7 +88,6 @@ void taosVariantCreate(SVariant *pVar, char* z, int32_t n, int32_t type) { } else { return; } - break; } @@ -60,38 +95,38 @@ void taosVariantCreate(SVariant *pVar, char* z, int32_t n, int32_t type) { case TSDB_DATA_TYPE_SMALLINT: case TSDB_DATA_TYPE_BIGINT: case TSDB_DATA_TYPE_INT:{ -// ret = tStrToInteger(token->z, token->type, token->n, &pVar->i64, true); -// if (ret != 0) { -// SToken t = {0}; -// tGetToken(token->z, &t.type); -// if (t.type == TK_MINUS) { // it is a signed number which is greater than INT64_MAX or less than INT64_MIN -// pVar->nType = -1; // -1 means error type -// return; -// } -// -// // data overflow, try unsigned parse the input number -// ret = tStrToInteger(token->z, token->type, token->n, &pVar->i64, false); -// if (ret != 0) { -// pVar->nType = -1; // -1 means error type -// return; -// } -// } + bool sign = true; + + int32_t base = 10; + if (type == TK_HEX) { + base = 16; + } else if (type == TK_OCT) { + base = 8; + } else if (type == TK_BIN) { + base = 2; + } + ret = toInteger(z, n, base, &pVar->i64, &sign); + if (ret != 0) { + pVar->nType = -1; // -1 means error type + return; + } + + pVar->nType = (sign)? TSDB_DATA_TYPE_BIGINT:TSDB_DATA_TYPE_UBIGINT; break; } - case TSDB_DATA_TYPE_DOUBLE: case TSDB_DATA_TYPE_FLOAT: { pVar->d = strtod(z, NULL); break; } - case TSDB_DATA_TYPE_BINARY: { pVar->pz = strndup(z, n); pVar->nLen = strRmquote(pVar->pz, n); break; } case TSDB_DATA_TYPE_TIMESTAMP: { + assert(0); pVar->i64 = taosGetTimestamp(TSDB_TIME_PRECISION_NANO); break; } diff --git a/source/common/test/CMakeLists.txt b/source/common/test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f4c849780db37fed93b93d800da1a50d75af53b5 --- /dev/null +++ b/source/common/test/CMakeLists.txt @@ -0,0 +1,18 @@ + +MESSAGE(STATUS "build parser unit test") + +# GoogleTest requires at least C++11 +SET(CMAKE_CXX_STANDARD 11) +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} SOURCE_LIST) + +ADD_EXECUTABLE(commonTest ${SOURCE_LIST}) +TARGET_LINK_LIBRARIES( + commonTest + PUBLIC os util common gtest +) + +TARGET_INCLUDE_DIRECTORIES( + commonTest + PUBLIC "${CMAKE_SOURCE_DIR}/include/libs/common/" + PRIVATE "${CMAKE_SOURCE_DIR}/source/libs/common/inc" +) diff --git a/source/common/test/commonTests.cpp b/source/common/test/commonTests.cpp index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2f821ee8b91dd8c5d9ff6b7e18c129c51618074e 100644 --- a/source/common/test/commonTests.cpp +++ b/source/common/test/commonTests.cpp @@ -0,0 +1,96 @@ +#include +#include +#pragma GCC diagnostic ignored "-Wwrite-strings" + +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wsign-compare" +#include "os.h" + +#include "taos.h" +#include "tvariant.h" +#include "tdef.h" + +namespace { +// +} // namespace + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +TEST(testCase, toInteger_test) { + char* s = "123"; + uint32_t type = 0; + + int64_t val = 0; + bool sign = true; + + int32_t ret = toInteger(s, strlen(s), 10, &val, &sign); + ASSERT_EQ(ret, 0); + ASSERT_EQ(val, 123); + ASSERT_EQ(sign, true); + + s = "9223372036854775807"; + ret = toInteger(s, strlen(s), 10, &val, &sign); + ASSERT_EQ(ret, 0); + ASSERT_EQ(val, 9223372036854775807); + ASSERT_EQ(sign, true); + + s = "9323372036854775807"; + ret = toInteger(s, strlen(s), 10, &val, &sign); + ASSERT_EQ(ret, 0); + ASSERT_EQ(val, 9323372036854775807u); + ASSERT_EQ(sign, false); + + s = "-9323372036854775807"; + ret = toInteger(s, strlen(s), 10, &val, &sign); + ASSERT_EQ(ret, -1); + + s = "-1"; + ret = toInteger(s, strlen(s), 10, &val, &sign); + ASSERT_EQ(ret, 0); + ASSERT_EQ(val, -1); + ASSERT_EQ(sign, true); + + s = "-9223372036854775807"; + ret = toInteger(s, strlen(s), 10, &val, &sign); + ASSERT_EQ(ret, 0); + ASSERT_EQ(val, -9223372036854775807); + ASSERT_EQ(sign, true); + + s = "1000u"; + ret = toInteger(s, strlen(s), 10, &val, &sign); + ASSERT_EQ(ret, -1); + + s = "0x10"; + ret = toInteger(s, strlen(s), 16, &val, &sign); + ASSERT_EQ(ret, 0); + ASSERT_EQ(val, 16); + ASSERT_EQ(sign, true); + + s = "110"; + ret = toInteger(s, strlen(s), 2, &val, &sign); + ASSERT_EQ(ret, 0); + ASSERT_EQ(val, 6); + ASSERT_EQ(sign, true); + + s = "110"; + ret = toInteger(s, strlen(s), 8, &val, &sign); + ASSERT_EQ(ret, 0); + ASSERT_EQ(val, 72); + ASSERT_EQ(sign, true); + + //18446744073709551615 UINT64_MAX + s = "18446744073709551615"; + ret = toInteger(s, strlen(s), 10, &val, &sign); + ASSERT_EQ(ret, 0); + ASSERT_EQ(val, 18446744073709551615u); + ASSERT_EQ(sign, false); + + s = "18446744073709551616"; + ret = toInteger(s, strlen(s), 10, &val, &sign); + ASSERT_EQ(ret, -1); +} diff --git a/source/libs/parser/inc/astGenerator.h b/source/libs/parser/inc/astGenerator.h index 14fa6152adb3883082f2493ed55a2681e05e480e..bf32bd6af96fc755694b337471339a34b1377c4d 100644 --- a/source/libs/parser/inc/astGenerator.h +++ b/source/libs/parser/inc/astGenerator.h @@ -277,6 +277,7 @@ bool tSqlExprIsParentOfLeaf(tSqlExpr *pExpr); void tSqlExprDestroy(tSqlExpr *pExpr); SArray * tSqlExprListAppend(SArray *pList, tSqlExpr *pNode, SToken *pDistinct, SToken *pToken); void tSqlExprListDestroy(SArray *pList); +void tSqlExprEvaluate(tSqlExpr* pExpr); SSqlNode *tSetQuerySqlNode(SToken *pSelectToken, SArray *pSelNodeList, SRelationInfo *pFrom, tSqlExpr *pWhere, SArray *pGroupby, SArray *pSortOrder, SIntervalVal *pInterval, SSessionWindowVal *ps, diff --git a/source/libs/parser/inc/parserInt.h b/source/libs/parser/inc/parserInt.h index 676b9f3d3130ce3ded2f06d1c2d667f04f15b069..cd01b60d703558ffe7276270694e2300f0ca5c34 100644 --- a/source/libs/parser/inc/parserInt.h +++ b/source/libs/parser/inc/parserInt.h @@ -46,6 +46,16 @@ typedef struct SInsertStmtInfo { */ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pSqlInfo, SQueryStmtInfo* pQueryInfo, int64_t id, char* msg, int32_t msgLen); +/** + * + * @param pNode + * @param tsPrecision + * @param msg + * @param msgBufLen + * @return + */ +int32_t evaluateSqlNode(SSqlNode* pNode, int32_t tsPrecision, char* msg, int32_t msgBufLen); + /** * * @param pSqlNode diff --git a/source/libs/parser/inc/parserUtil.h b/source/libs/parser/inc/parserUtil.h index c4e821a4c9c93d6b547505fb2d2e63050db2a1e7..ee69abf6c56640f207e6aebe294e172ec7c8e523 100644 --- a/source/libs/parser/inc/parserUtil.h +++ b/source/libs/parser/inc/parserUtil.h @@ -23,7 +23,8 @@ extern "C" { #include "os.h" #include "ttoken.h" -int32_t parserValidateNameToken(SToken* pToken); +int32_t parserValidateIdToken(SToken* pToken); +int32_t parserSetInvalidOperatorMsg(char* dst, int32_t dstBufLen, const char* msg); #ifdef __cplusplus } diff --git a/source/libs/parser/src/astGenerator.c b/source/libs/parser/src/astGenerator.c index 2c5f0f90a4fc976e6bccccf65be269dca0b85022..e9517758d1086eb2b8fe8ee005a0318ba6c3d5ae 100644 --- a/source/libs/parser/src/astGenerator.c +++ b/source/libs/parser/src/astGenerator.c @@ -18,52 +18,6 @@ #include "astGenerator.h" #include "tmsgtype.h" -int32_t tStrToInteger(const char* z, int16_t type, int32_t n, int64_t* value, bool issigned) { - errno = 0; - int32_t ret = 0; - - char* endPtr = NULL; - if (type == TK_FLOAT) { - double v = strtod(z, &endPtr); - if ((errno == ERANGE && v == HUGE_VALF) || isinf(v) || isnan(v)) { - ret = -1; - } else if ((issigned && (v < INT64_MIN || v > INT64_MAX)) || ((!issigned) && (v < 0 || v > UINT64_MAX))) { - ret = -1; - } else { - *value = (int64_t) round(v); - } - - errno = 0; - return ret; - } - - int32_t radix = 10; - if (type == TK_HEX) { - radix = 16; - } else if (type == TK_BIN) { - radix = 2; - } - - // the string may be overflow according to errno - if (!issigned) { - const char *p = z; - while(*p != 0 && *p == ' ') p++; - if (*p != 0 && *p == '-') { return -1;} - - *value = strtoull(z, &endPtr, radix); - } else { - *value = strtoll(z, &endPtr, radix); - } - - // not a valid integer number, return error - if (endPtr - z != n || errno == ERANGE) { - ret = -1; - } - - errno = 0; - return ret; -} - SArray *tListItemAppend(SArray *pList, SVariant *pVar, uint8_t sortOrder) { if (pList == NULL) { pList = taosArrayInit(4, sizeof(SListItem)); @@ -173,7 +127,6 @@ SRelationInfo *addSubquery(SRelationInfo *pRelationInfo, SArray *pSub, SToken *p } // sql expr leaf node -// todo Evalute the value during the validation process of AST. tSqlExpr *tSqlExprCreateIdValue(SToken *pToken, int32_t optrType) { tSqlExpr *pSqlExpr = calloc(1, sizeof(tSqlExpr)); @@ -189,34 +142,10 @@ tSqlExpr *tSqlExprCreateIdValue(SToken *pToken, int32_t optrType) { pSqlExpr->tokenId = optrType; pSqlExpr->type = SQL_NODE_VALUE; } else if (optrType == TK_INTEGER || optrType == TK_STRING || optrType == TK_FLOAT || optrType == TK_BOOL) { -// if (pToken) { -// toTSDBType(pToken->type); -// tVariantCreate(&pSqlExpr->value, pToken); -// } pSqlExpr->tokenId = optrType; pSqlExpr->type = SQL_NODE_VALUE; - } else if (optrType == TK_NOW) { - // use nanosecond by default TODO set value after getting database precision -// pSqlExpr->value.i64 = taosGetTimestamp(TSDB_TIME_PRECISION_NANO); -// pSqlExpr->value.nType = TSDB_DATA_TYPE_BIGINT; - pSqlExpr->tokenId = TK_TIMESTAMP; // TK_TIMESTAMP used to denote the time value is in microsecond - pSqlExpr->type = SQL_NODE_VALUE; -// pSqlExpr->flags |= 1 << EXPR_FLAG_NS_TIMESTAMP; - } else if (optrType == TK_VARIABLE) { - // use nanosecond by default - // TODO set value after getting database precision -// if (pToken) { -// char unit = 0; -// int32_t ret = parseAbsoluteDuration(pToken->z, pToken->n, &pSqlExpr->value.i64, &unit, TSDB_TIME_PRECISION_NANO); -// if (ret != TSDB_CODE_SUCCESS) { -// terrno = TSDB_CODE_TSC_SQL_SYNTAX_ERROR; -// } -// } - -// pSqlExpr->flags |= 1 << EXPR_FLAG_NS_TIMESTAMP; -// pSqlExpr->flags |= 1 << EXPR_FLAG_TIMESTAMP_VAR; -// pSqlExpr->value.nType = TSDB_DATA_TYPE_BIGINT; - pSqlExpr->tokenId = TK_TIMESTAMP; + } else if (optrType == TK_NOW || optrType == TK_VARIABLE) { + pSqlExpr->tokenId = optrType; // TK_TIMESTAMP used to denote this is a timestamp value pSqlExpr->type = SQL_NODE_VALUE; } else { // Here it must be the column name (tk_id) if it is not a number or string. @@ -269,87 +198,7 @@ tSqlExpr *tSqlExprCreate(tSqlExpr *pLeft, tSqlExpr *pRight, int32_t optrType) { pExpr->exprToken.type = pLeft->exprToken.type; } - if ((pLeft != NULL && pRight != NULL) && - (optrType == TK_PLUS || optrType == TK_MINUS || optrType == TK_STAR || optrType == TK_DIVIDE || optrType == TK_REM)) { - /* - * if a exprToken is noted as the TK_TIMESTAMP, the time precision is microsecond - * Otherwise, the time precision is adaptive, determined by the time precision from databases. - */ - if ((pLeft->tokenId == TK_INTEGER && pRight->tokenId == TK_INTEGER) || - (pLeft->tokenId == TK_TIMESTAMP && pRight->tokenId == TK_TIMESTAMP)) { - pExpr->value.nType = TSDB_DATA_TYPE_BIGINT; - pExpr->tokenId = pLeft->tokenId; - pExpr->type = SQL_NODE_VALUE; - - switch (optrType) { - case TK_PLUS: { - pExpr->value.i64 = pLeft->value.i64 + pRight->value.i64; - break; - } - case TK_MINUS: { - pExpr->value.i64 = pLeft->value.i64 - pRight->value.i64; - break; - } - case TK_STAR: { - pExpr->value.i64 = pLeft->value.i64 * pRight->value.i64; - break; - } - case TK_DIVIDE: { - pExpr->tokenId = TK_FLOAT; - pExpr->value.nType = TSDB_DATA_TYPE_DOUBLE; - pExpr->value.d = (double)pLeft->value.i64 / pRight->value.i64; - break; - } - case TK_REM: { - pExpr->value.i64 = pLeft->value.i64 % pRight->value.i64; - break; - } - } - - tSqlExprDestroy(pLeft); - tSqlExprDestroy(pRight); - } else if ((pLeft->tokenId == TK_FLOAT && pRight->tokenId == TK_INTEGER) || - (pLeft->tokenId == TK_INTEGER && pRight->tokenId == TK_FLOAT) || - (pLeft->tokenId == TK_FLOAT && pRight->tokenId == TK_FLOAT)) { - pExpr->value.nType = TSDB_DATA_TYPE_DOUBLE; - pExpr->tokenId = TK_FLOAT; - pExpr->type = SQL_NODE_VALUE; - - double left = (pLeft->value.nType == TSDB_DATA_TYPE_DOUBLE) ? pLeft->value.d : pLeft->value.i64; - double right = (pRight->value.nType == TSDB_DATA_TYPE_DOUBLE) ? pRight->value.d : pRight->value.i64; - - switch (optrType) { - case TK_PLUS: { - pExpr->value.d = left + right; - break; - } - case TK_MINUS: { - pExpr->value.d = left - right; - break; - } - case TK_STAR: { - pExpr->value.d = left * right; - break; - } - case TK_DIVIDE: { - pExpr->value.d = left / right; - break; - } - case TK_REM: { - pExpr->value.d = left - ((int64_t)(left / right)) * right; - break; - } - } - - tSqlExprDestroy(pLeft); - tSqlExprDestroy(pRight); - - } else { - pExpr->tokenId = optrType; - pExpr->pLeft = pLeft; - pExpr->pRight = pRight; - } - } else if (optrType == TK_IN) { + if (optrType == TK_IN) { pExpr->tokenId = optrType; pExpr->pLeft = pLeft; @@ -501,6 +350,105 @@ void tSqlExprListDestroy(SArray *pList) { taosArrayDestroyEx(pList, freeExprElem); } +void tSqlExprEvaluate(tSqlExpr* pExpr) { + tSqlExpr *pLeft = pExpr->pLeft; + tSqlExpr *pRight = pExpr->pRight; + + if (pLeft == NULL || pRight == NULL) { + return; + } + + int32_t optrType = pExpr->tokenId; + + if ((optrType == TK_PLUS || optrType == TK_MINUS || optrType == TK_STAR || optrType == TK_DIVIDE || + optrType == TK_REM)) { + /* + * if a exprToken is noted as the TK_TIMESTAMP, the time precision is microsecond + * Otherwise, the time precision is adaptive, determined by the time precision from databases. + */ + int32_t ltoken = pLeft->tokenId; + int32_t rtoken = pRight->tokenId; + + if ((ltoken == TK_INTEGER && rtoken == TK_INTEGER) || (ltoken == TK_TIMESTAMP && rtoken == TK_TIMESTAMP)) { + pExpr->value.nType = TSDB_DATA_TYPE_BIGINT; + pExpr->tokenId = ltoken; + pExpr->type = SQL_NODE_VALUE; + + switch (optrType) { + case TK_PLUS: { + pExpr->value.i64 = pLeft->value.i64 + pRight->value.i64; + break; + } + case TK_MINUS: { + pExpr->value.i64 = pLeft->value.i64 - pRight->value.i64; + break; + } + case TK_STAR: { + pExpr->value.i64 = pLeft->value.i64 * pRight->value.i64; + break; + } + case TK_DIVIDE: { + pExpr->tokenId = TK_FLOAT; + pExpr->value.nType = TSDB_DATA_TYPE_DOUBLE; + pExpr->value.d = (double)pLeft->value.i64 / pRight->value.i64; + break; + } + case TK_REM: { + pExpr->value.i64 = pLeft->value.i64 % pRight->value.i64; + break; + } + default: + assert(0); + } + + tSqlExprDestroy(pLeft); + tSqlExprDestroy(pRight); + + pExpr->pLeft = NULL; + pExpr->pRight = NULL; + } else if ((ltoken == TK_FLOAT && rtoken == TK_INTEGER) || (ltoken == TK_INTEGER && rtoken == TK_FLOAT) || + (ltoken == TK_FLOAT && rtoken == TK_FLOAT)) { + pExpr->value.nType = TSDB_DATA_TYPE_DOUBLE; + pExpr->tokenId = TK_FLOAT; + pExpr->type = SQL_NODE_VALUE; + + double left = (pLeft->value.nType == TSDB_DATA_TYPE_DOUBLE) ? pLeft->value.d : pLeft->value.i64; + double right = (pRight->value.nType == TSDB_DATA_TYPE_DOUBLE) ? pRight->value.d : pRight->value.i64; + + switch (optrType) { + case TK_PLUS: { + pExpr->value.d = left + right; + break; + } + case TK_MINUS: { + pExpr->value.d = left - right; + break; + } + case TK_STAR: { + pExpr->value.d = left * right; + break; + } + case TK_DIVIDE: { + pExpr->value.d = left / right; + break; + } + case TK_REM: { + pExpr->value.d = left - ((int64_t)(left / right)) * right; + break; + } + default: + assert(0); + } + + tSqlExprDestroy(pLeft); + tSqlExprDestroy(pRight); + + pExpr->pLeft = NULL; + pExpr->pRight = NULL; + } + } +} + SSqlNode *tSetQuerySqlNode(SToken *pSelectToken, SArray *pSelNodeList, SRelationInfo *pFrom, tSqlExpr *pWhere, SArray *pGroupby, SArray *pSortOrder, SIntervalVal *pInterval, SSessionWindowVal *pSession, SWindowStateVal *pWindowStateVal, SToken *pSliding, SArray *pFill, SLimit *pLimit, diff --git a/source/libs/parser/src/astValidate.c b/source/libs/parser/src/astValidate.c index 3b3e80c00f3aedb2e2b8e6db398139da61aef025..132fcd6801825c5e136908583cdd01bbc764e0b6 100644 --- a/source/libs/parser/src/astValidate.c +++ b/source/libs/parser/src/astValidate.c @@ -13,13 +13,82 @@ * along with this program. If not, see . */ +#include "ttime.h" #include "parserInt.h" #include "parserUtil.h" -#include "tmsgtype.h" -static int32_t setInvalidOperatorErrMsg(char* dst, int32_t dstBufLen, const char* msg) { - strncpy(dst, msg, dstBufLen); - return TSDB_CODE_TSC_INVALID_OPERATION; +static int32_t evaluateImpl(tSqlExpr* pExpr, int32_t tsPrecision) { + int32_t code = 0; + if (pExpr->type == SQL_NODE_EXPR) { + code = evaluateImpl(pExpr->pLeft, tsPrecision); + if (code != TSDB_CODE_SUCCESS) { + return code; + } + + code = evaluateImpl(pExpr->pRight, tsPrecision); + if (code != TSDB_CODE_SUCCESS) { + return code; + } + + if (pExpr->pLeft->type == SQL_NODE_VALUE && pExpr->pRight->type == SQL_NODE_VALUE) { + tSqlExpr* pLeft = pExpr->pLeft; + tSqlExpr* pRight = pExpr->pRight; + if ((pLeft->tokenId == TK_TIMESTAMP && (pRight->tokenId == TK_INTEGER || pRight->tokenId == TK_FLOAT)) || + ((pRight->tokenId == TK_TIMESTAMP && (pLeft->tokenId == TK_INTEGER || pLeft->tokenId == TK_FLOAT)))) { + return TSDB_CODE_TSC_SQL_SYNTAX_ERROR; + } else if (pLeft->tokenId == TK_TIMESTAMP && pRight->tokenId == TK_TIMESTAMP) { + tSqlExprEvaluate(pExpr); + } else { + tSqlExprEvaluate(pExpr); + } + } else { + // Other types of expressions are not evaluated, they will be handled during the validation of the abstract syntax tree. + } + } else if (pExpr->type == SQL_NODE_VALUE) { + if (pExpr->tokenId == TK_NOW) { + pExpr->value.i64 = taosGetTimestamp(tsPrecision); + pExpr->value.nType = TSDB_DATA_TYPE_BIGINT; + pExpr->tokenId = TK_TIMESTAMP; + } else if (pExpr->tokenId == TK_VARIABLE) { + char unit = 0; + SToken* pToken = &pExpr->exprToken; + int32_t ret = parseAbsoluteDuration(pToken->z, pToken->n, &pExpr->value.i64, &unit, tsPrecision); + if (ret != TSDB_CODE_SUCCESS) { + return TSDB_CODE_TSC_SQL_SYNTAX_ERROR; + } + + pExpr->value.nType = TSDB_DATA_TYPE_BIGINT; + pExpr->tokenId = TK_TIMESTAMP; + } else if (pExpr->tokenId == TK_NULL) { + pExpr->value.nType = TSDB_DATA_TYPE_NULL; + } else if (pExpr->tokenId == TK_INTEGER || pExpr->tokenId == TK_STRING || pExpr->tokenId == TK_FLOAT || pExpr->tokenId == TK_BOOL) { + SToken* pToken = &pExpr->exprToken; + + int32_t tokenType = pToken->type; + toTSDBType(tokenType); + taosVariantCreate(&pExpr->value, pToken->z, pToken->n, tokenType); + } + + return TSDB_CODE_SUCCESS; + // other types of data are handled in the parent level. + } + + return TSDB_CODE_SUCCESS; +} + +int32_t evaluateSqlNode(SSqlNode* pNode, int32_t tsPrecision, char* msg, int32_t msgBufLen) { + assert(pNode != NULL && msg != NULL && msgBufLen > 0); + if (pNode->pWhere == NULL) { + return TSDB_CODE_SUCCESS; + } + + int32_t code = evaluateImpl(pNode->pWhere, tsPrecision); + if (code != TSDB_CODE_SUCCESS) { + strncpy(msg, "invalid time expression in sql", msgBufLen); + return code; + } + + return code; } int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQueryStmtInfo* pQueryInfo, int64_t id, char* msgBuf, int32_t msgBufLen) { @@ -37,15 +106,15 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer const char* msg2 = "invalid name"; SToken* pzName = taosArrayGet(pInfo->pMiscInfo->a, 0); - if ((pInfo->type != TSDB_SQL_DROP_DNODE) && (parserValidateNameToken(pzName) != TSDB_CODE_SUCCESS)) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg2); + if ((pInfo->type != TSDB_SQL_DROP_DNODE) && (parserValidateIdToken(pzName) != TSDB_CODE_SUCCESS)) { + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg2); } if (pInfo->type == TSDB_SQL_DROP_DB) { assert(taosArrayGetSize(pInfo->pMiscInfo->a) == 1); code = tNameSetDbName(&pTableMetaInfo->name, getAccountId(pSql), pzName); if (code != TSDB_CODE_SUCCESS) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg2); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg2); } } else if (pInfo->type == TSDB_SQL_DROP_TABLE) { @@ -62,7 +131,7 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer strncpy(pCmd->payload, pzName->z, pzName->n); } else { // drop user/account if (pzName->n >= TSDB_USER_LEN) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg3); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg3); } strncpy(pCmd->payload, pzName->z, pzName->n); @@ -76,12 +145,12 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer SToken* pToken = taosArrayGet(pInfo->pMiscInfo->a, 0); if (tscValidateName(pToken) != TSDB_CODE_SUCCESS) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg); } int32_t ret = tNameSetDbName(&pTableMetaInfo->name, getAccountId(pSql), pToken); if (ret != TSDB_CODE_SUCCESS) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg); } break; @@ -116,19 +185,19 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer SCreateDbInfo* pCreateDB = &(pInfo->pMiscInfo->dbOpt); if (pCreateDB->dbname.n >= TSDB_DB_NAME_LEN) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg2); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg2); } char buf[TSDB_DB_NAME_LEN] = {0}; SToken token = taosTokenDup(&pCreateDB->dbname, buf, tListLen(buf)); if (tscValidateName(&token) != TSDB_CODE_SUCCESS) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg1); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg1); } int32_t ret = tNameSetDbName(&pTableMetaInfo->name, getAccountId(pSql), &token); if (ret != TSDB_CODE_SUCCESS) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg2); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg2); } if (parseCreateDBOptions(pCmd, pCreateDB) != TSDB_CODE_SUCCESS) { @@ -142,7 +211,7 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer const char* msg = "invalid host name (ip address)"; if (taosArrayGetSize(pInfo->pMiscInfo->a) > 1) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg); } SToken* id = taosArrayGet(pInfo->pMiscInfo->a, 0); @@ -166,11 +235,11 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer } if (pName->n >= TSDB_USER_LEN) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg3); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg3); } if (tscValidateName(pName) != TSDB_CODE_SUCCESS) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg2); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg2); } SCreateAcctInfo* pAcctOpt = &pInfo->pMiscInfo->acctOpt; @@ -180,7 +249,7 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer } else if (strncmp(pAcctOpt->stat.z, "all", 3) == 0 && pAcctOpt->stat.n == 3) { } else if (strncmp(pAcctOpt->stat.z, "no", 2) == 0 && pAcctOpt->stat.n == 2) { } else { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg1); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg1); } } @@ -192,7 +261,7 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer SToken* pToken = taosArrayGet(pInfo->pMiscInfo->a, 0); if (tscValidateName(pToken) != TSDB_CODE_SUCCESS) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg1); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg1); } // additional msg has been attached already code = tscSetTableFullName(&pTableMetaInfo->name, pToken, pSql); @@ -208,7 +277,7 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer SToken* pToken = taosArrayGet(pInfo->pMiscInfo->a, 0); if (tscValidateName(pToken) != TSDB_CODE_SUCCESS) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg1); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg1); } code = tscSetTableFullName(&pTableMetaInfo->name, pToken, pSql); @@ -223,11 +292,11 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer SToken* pToken = taosArrayGet(pInfo->pMiscInfo->a, 0); if (tscValidateName(pToken) != TSDB_CODE_SUCCESS) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg1); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg1); } if (pToken->n > TSDB_DB_NAME_LEN) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg1); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg1); } return tNameSetDbName(&pTableMetaInfo->name, getAccountId(pSql), pToken); } @@ -240,7 +309,7 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer /* validate the parameter names and options */ if (validateDNodeConfig(pMiscInfo) != TSDB_CODE_SUCCESS) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg2); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg2); } char* pMsg = pCmd->payload; @@ -254,7 +323,7 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer strncpy(pCfg->ep, t0->z, t0->n); if (validateEp(pCfg->ep) != TSDB_CODE_SUCCESS) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg3); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg3); } strncpy(pCfg->config, t1->z, t1->n); @@ -283,11 +352,11 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer SToken* pPwd = &pUser->passwd; if (pName->n >= TSDB_USER_LEN) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg3); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg3); } if (tscValidateName(pName) != TSDB_CODE_SUCCESS) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg2); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg2); } if (pCmd->command == TSDB_SQL_CREATE_USER) { @@ -311,10 +380,10 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer } else if (strncasecmp(pPrivilege->z, "write", 5) == 0 && pPrivilege->n == 5) { pCmd->count = 3; } else { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg5); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg5); } } else { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg7); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg7); } } @@ -327,7 +396,7 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer // validate the parameter names and options if (validateLocalConfig(pMiscInfo) != TSDB_CODE_SUCCESS) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg); } int32_t numOfToken = (int32_t) taosArrayGetSize(pMiscInfo->a); @@ -382,7 +451,7 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer tscTrace("0x%"PRIx64" start to parse the %dth subclause, total:%"PRIzu, pSql->self, i, size); if (size > 1 && pSqlNode->from && pSqlNode->from->type == SQL_NODE_FROM_SUBQUERY) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg1); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg1); } // normalizeSqlNode(pSqlNode); // normalize the column name in each function @@ -448,19 +517,19 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQuer assert(taosArrayGetSize(pInfo->pMiscInfo->a) == 1); code = tNameSetDbName(&pTableMetaInfo->name, getAccountId(pSql), pzName); if (code != TSDB_CODE_SUCCESS) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg1); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg1); } break; } case TSDB_SQL_COMPACT_VNODE:{ const char* msg = "invalid compact"; if (setCompactVnodeInfo(pSql, pInfo) != TSDB_CODE_SUCCESS) { - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg); + return setInvalidOperatorMsg(msgBuf, msgBufLen, msg); } break; } default: - return setInvalidOperatorErrMsg(msgBuf, msgBufLen, "not support sql expression"); + return setInvalidOperatorMsg(msgBuf, msgBufLen, "not support sql expression"); } #endif diff --git a/source/libs/parser/src/parser.c b/source/libs/parser/src/parser.c index d7f9fca226392eec02ed182bf3f110e61bc4ebf1..9709c5ad6559bdfae7de5e3ddf2c2cf04f1ae42c 100644 --- a/source/libs/parser/src/parser.c +++ b/source/libs/parser/src/parser.c @@ -16,6 +16,7 @@ #include "parserInt.h" #include "ttoken.h" #include "astGenerator.h" +#include "parserUtil.h" bool qIsInsertSql(const char* pStr, size_t length) { return false; @@ -50,6 +51,216 @@ int32_t qParserConvertSql(const char* pStr, size_t length, char** pConvertSql) { return 0; } -int32_t qParserExtractRequestedMetaInfo(const SArray* pSqlNodeList, SMetaReq* pMetaInfo) { - return 0; +static int32_t getTableNameFromSubquery(SSqlNode* pSqlNode, SArray* tableNameList, char* msgBuf) { + int32_t numOfSub = (int32_t)taosArrayGetSize(pSqlNode->from->list); + + for (int32_t j = 0; j < numOfSub; ++j) { + SRelElementPair* sub = taosArrayGet(pSqlNode->from->list, j); + + int32_t num = (int32_t)taosArrayGetSize(sub->pSubquery); + for (int32_t i = 0; i < num; ++i) { + SSqlNode* p = taosArrayGetP(sub->pSubquery, i); + if (p->from->type == SQL_NODE_FROM_TABLELIST) { + int32_t code = getTableNameFromSqlNode(p, tableNameList, msgBuf); + if (code != TSDB_CODE_SUCCESS) { + return code; + } + } else { + getTableNameFromSubquery(p, tableNameList, msgBuf); + } + } + } + + return TSDB_CODE_SUCCESS; +} + +static int32_t getTableNameFromSqlNode(SSqlNode* pSqlNode, SArray* tableNameList, char* msg, int32_t msgBufLen) { + const char* msg1 = "invalid table name"; + + int32_t numOfTables = (int32_t) taosArrayGetSize(pSqlNode->from->list); + assert(pSqlNode->from->type == SQL_NODE_FROM_TABLELIST); + + for(int32_t j = 0; j < numOfTables; ++j) { + SRelElementPair* item = taosArrayGet(pSqlNode->from->list, j); + + SToken* t = &item->tableName; + if (t->type == TK_INTEGER || t->type == TK_FLOAT) { + return parserSetInvalidOperatorMsg(msg, msgBufLen, msg1); + } + + tscDequoteAndTrimToken(t); + if (parserValidateIdToken(t) != TSDB_CODE_SUCCESS) { + return parserSetInvalidOperatorMsg(msg, msgBufLen, msg1); + } + + SName name = {0}; + int32_t code = tscSetTableFullName(&name, t, pSql); + if (code != TSDB_CODE_SUCCESS) { + return code; + } + + taosArrayPush(tableNameList, &name); + } + + return TSDB_CODE_SUCCESS; +} + +int32_t qParserExtractRequestedMetaInfo(const SArray* pSqlNodeList, SMetaReq* pMetaInfo, char* msg, int32_t msgBufLen) { + int32_t code = TSDB_CODE_SUCCESS; + + SArray* tableNameList = NULL; + SArray* pVgroupList = NULL; + SArray* plist = NULL; + STableMeta* pTableMeta = NULL; +// size_t tableMetaCapacity = 0; +// SQueryInfo* pQueryInfo = tscGetQueryInfo(pCmd); + +// pCmd->pTableMetaMap = taosHashInit(4, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_NO_LOCK); + + tableNameList = taosArrayInit(4, sizeof(SName)); + size_t size = taosArrayGetSize(pSqlNodeList); + for (int32_t i = 0; i < size; ++i) { + SSqlNode* pSqlNode = taosArrayGetP(pSqlNodeList, i); + if (pSqlNode->from == NULL) { + goto _end; + } + + // load the table meta in the from clause + if (pSqlNode->from->type == SQL_NODE_FROM_TABLELIST) { + code = getTableNameFromSqlNode(pSqlNode, tableNameList, msg, msgBufLen); + if (code != TSDB_CODE_SUCCESS) { + goto _end; + } + } else { + code = getTableNameFromSubquery(pSqlNode, tableNameList, msg, msgBufLen); + if (code != TSDB_CODE_SUCCESS) { + goto _end; + } + } + } + + char name[TSDB_TABLE_FNAME_LEN] = {0}; + + plist = taosArrayInit(4, POINTER_BYTES); + pVgroupList = taosArrayInit(4, POINTER_BYTES); + + taosArraySort(tableNameList, tnameComparFn); + taosArrayRemoveDuplicate(tableNameList, tnameComparFn, NULL); + + STableMeta* pSTMeta = (STableMeta *)(pSql->pBuf); + size_t numOfTables = taosArrayGetSize(tableNameList); + for (int32_t i = 0; i < numOfTables; ++i) { + SName* pname = taosArrayGet(tableNameList, i); + tNameExtractFullName(pname, name); + + size_t len = strlen(name); + + if (NULL == taosHashGetCloneExt(tscTableMetaMap, name, len, NULL, (void **)&pTableMeta, &tableMetaCapacity)) { + // not found + tfree(pTableMeta); + } + + if (pTableMeta && pTableMeta->id.uid > 0) { + tscDebug("0x%"PRIx64" retrieve table meta %s from local buf", pSql->self, name); + + // avoid mem leak, may should update pTableMeta + void* pVgroupIdList = NULL; + if (pTableMeta->tableType == TSDB_CHILD_TABLE) { + code = tscCreateTableMetaFromSTableMeta((STableMeta **)(&pTableMeta), name, &tableMetaCapacity, (STableMeta **)(&pSTMeta)); + pSql->pBuf = (void *)pSTMeta; + + // create the child table meta from super table failed, try load it from mnode + if (code != TSDB_CODE_SUCCESS) { + char* t = strdup(name); + taosArrayPush(plist, &t); + continue; + } + } else if (pTableMeta->tableType == TSDB_SUPER_TABLE) { + // the vgroup list of super table is not kept in local buffer, so here need retrieve it from the mnode each time + tscDebug("0x%"PRIx64" try to acquire cached super table %s vgroup id list", pSql->self, name); + void* pv = taosCacheAcquireByKey(tscVgroupListBuf, name, len); + if (pv == NULL) { + char* t = strdup(name); + taosArrayPush(pVgroupList, &t); + tscDebug("0x%"PRIx64" failed to retrieve stable %s vgroup id list in cache, try fetch from mnode", pSql->self, name); + } else { + tFilePage* pdata = (tFilePage*) pv; + pVgroupIdList = taosArrayInit((size_t) pdata->num, sizeof(int32_t)); + if (pVgroupIdList == NULL) { + return TSDB_CODE_TSC_OUT_OF_MEMORY; + } + + taosArrayAddBatch(pVgroupIdList, pdata->data, (int32_t) pdata->num); + taosCacheRelease(tscVgroupListBuf, &pv, false); + } + } + + if (taosHashGet(pCmd->pTableMetaMap, name, len) == NULL) { + STableMeta* pMeta = tscTableMetaDup(pTableMeta); + STableMetaVgroupInfo tvi = { .pTableMeta = pMeta, .vgroupIdList = pVgroupIdList}; + taosHashPut(pCmd->pTableMetaMap, name, len, &tvi, sizeof(STableMetaVgroupInfo)); + } + } else { + // Add to the retrieve table meta array list. + // If the tableMeta is missing, the cached vgroup list for the corresponding super table will be ignored. + tscDebug("0x%"PRIx64" failed to retrieve table meta %s from local buf", pSql->self, name); + + char* t = strdup(name); + taosArrayPush(plist, &t); + } + } + + size_t funcSize = 0; + if (pInfo->funcs) { + funcSize = taosArrayGetSize(pInfo->funcs); + } + + if (funcSize > 0) { + for (size_t i = 0; i < funcSize; ++i) { + SToken* t = taosArrayGet(pInfo->funcs, i); + if (NULL == t) { + continue; + } + + if (t->n >= TSDB_FUNC_NAME_LEN) { + code = tscSQLSyntaxErrMsg(tscGetErrorMsgPayload(pCmd), "too long function name", t->z); + if (code != TSDB_CODE_SUCCESS) { + goto _end; + } + } + + int32_t functionId = isValidFunction(t->z, t->n); + if (functionId < 0) { + struct SUdfInfo info = {0}; + info.name = strndup(t->z, t->n); + if (pQueryInfo->pUdfInfo == NULL) { + pQueryInfo->pUdfInfo = taosArrayInit(4, sizeof(struct SUdfInfo)); + } + + info.functionId = (int32_t)taosArrayGetSize(pQueryInfo->pUdfInfo) * (-1) - 1;; + taosArrayPush(pQueryInfo->pUdfInfo, &info); + } + } + } + + // load the table meta for a given table name list + if (taosArrayGetSize(plist) > 0 || taosArrayGetSize(pVgroupList) > 0 || (pQueryInfo->pUdfInfo && taosArrayGetSize(pQueryInfo->pUdfInfo) > 0)) { + code = getMultiTableMetaFromMnode(pSql, plist, pVgroupList, pQueryInfo->pUdfInfo, tscTableMetaCallBack, true); + } + + _end: + if (plist != NULL) { + taosArrayDestroyEx(plist, freeElem); + } + + if (pVgroupList != NULL) { + taosArrayDestroyEx(pVgroupList, freeElem); + } + + if (tableNameList != NULL) { + taosArrayDestroy(tableNameList); + } + + tfree(pTableMeta); + return code; } \ No newline at end of file diff --git a/source/libs/parser/src/parserUtil.c b/source/libs/parser/src/parserUtil.c index 77b8e9e789cc6d155314e83b9ac0bdfca97f53b9..420306e97001daa1131cbc5bcbaeb5e7e9f3b283 100644 --- a/source/libs/parser/src/parserUtil.c +++ b/source/libs/parser/src/parserUtil.c @@ -2,7 +2,7 @@ #include "taoserror.h" #include "tutil.h" -int32_t parserValidateNameToken(SToken* pToken) { +int32_t parserValidateIdToken(SToken* pToken) { if (pToken == NULL || pToken->z == NULL || pToken->type != TK_ID) { return TSDB_CODE_TSC_INVALID_OPERATION; } @@ -57,4 +57,9 @@ int32_t parserValidateNameToken(SToken* pToken) { } return TSDB_CODE_SUCCESS; +} + +int32_t parserSetInvalidOperatorMsg(char* dst, int32_t dstBufLen, const char* msg) { + strncpy(dst, msg, dstBufLen); + return TSDB_CODE_TSC_INVALID_OPERATION; } \ No newline at end of file diff --git a/source/libs/parser/src/ttokenizer.c b/source/libs/parser/src/ttokenizer.c index 5e3cefea10386fb5ba09047182c8abe824b49d81..b71fb4538e514eb67702d7a5f1e829d87a07f7a6 100644 --- a/source/libs/parser/src/ttokenizer.c +++ b/source/libs/parser/src/ttokenizer.c @@ -411,6 +411,7 @@ uint32_t tGetToken(char* z, uint32_t* tokenId) { *tokenId = TK_QUESTION; return 1; } + case '`': case '\'': case '"': { int delim = z[0]; @@ -434,7 +435,7 @@ uint32_t tGetToken(char* z, uint32_t* tokenId) { if (z[i]) i++; if (strEnd) { - *tokenId = TK_STRING; + *tokenId = (delim == '`')? TK_ID:TK_STRING; return i; } diff --git a/source/libs/parser/test/tokenizerTest.cpp b/source/libs/parser/test/tokenizerTest.cpp index 2a3bdbed5407b35e530c4ad353edd749d195eee0..5aca0077f487b2625476105dc651725a10716a41 100644 --- a/source/libs/parser/test/tokenizerTest.cpp +++ b/source/libs/parser/test/tokenizerTest.cpp @@ -14,6 +14,7 @@ #include "ttoken.h" #include "astGenerator.h" #include "parserUtil.h" +#include "parserInt.h" namespace { int32_t testValidateName(char* name) { @@ -23,7 +24,7 @@ int32_t testValidateName(char* name) { token.type = 0; tGetToken(name, &token.type); - return parserValidateNameToken(&token); + return parserValidateIdToken(&token); } SToken createToken(char* s) { @@ -667,4 +668,29 @@ TEST(testCase, isValidNumber_test) { TEST(testCase, generateAST_test) { SSqlInfo info = doGenerateAST("select * from t1 where ts < now"); ASSERT_EQ(info.valid, true); -} \ No newline at end of file + + SSqlInfo info1 = doGenerateAST("select * from `t.1abc` where ts