提交 1d5f98fe 编写于 作者: H Haojun Liao

[td-10529]Add unit test for parser module.

上级 a5359084
......@@ -24,26 +24,20 @@ extern "C" {
#define TSDB__packed
#ifdef TSKEY32
#define TSKEY int32_t;
#else
#define TSKEY int64_t
#endif
#define TSKEY_INITIAL_VAL INT64_MIN
// Bytes for each type.
extern const int32_t TYPE_BYTES[15];
// TODO: replace and remove code below
#define CHAR_BYTES sizeof(char)
#define SHORT_BYTES sizeof(int16_t)
#define INT_BYTES sizeof(int32_t)
#define LONG_BYTES sizeof(int64_t)
#define FLOAT_BYTES sizeof(float)
#define DOUBLE_BYTES sizeof(double)
#define POINTER_BYTES sizeof(void *) // 8 by default assert(sizeof(ptrdiff_t) == sizseof(void*)
#define CHAR_BYTES sizeof(char)
#define SHORT_BYTES sizeof(int16_t)
#define INT_BYTES sizeof(int32_t)
#define LONG_BYTES sizeof(int64_t)
#define FLOAT_BYTES sizeof(float)
#define DOUBLE_BYTES sizeof(double)
#define POINTER_BYTES sizeof(void *) // 8 by default assert(sizeof(ptrdiff_t) == sizseof(void*)
#define TSDB_KEYSIZE sizeof(TSKEY)
#define TSDB_NCHAR_SIZE sizeof(int32_t)
......@@ -88,9 +82,9 @@ extern const int32_t TYPE_BYTES[15];
#define TS_PATH_DELIMITER "."
#define TSDB_TIME_PRECISION_MILLI 0
#define TSDB_TIME_PRECISION_MICRO 1
#define TSDB_TIME_PRECISION_NANO 2
#define TSDB_TIME_PRECISION_MILLI 0
#define TSDB_TIME_PRECISION_MICRO 1
#define TSDB_TIME_PRECISION_NANO 2
#define TSDB_TIME_PRECISION_MILLI_STR "ms"
#define TSDB_TIME_PRECISION_MICRO_STR "us"
......@@ -412,44 +406,6 @@ do { \
#define TSDB_DATA_TYPE_UINT 13 // 4 bytes
#define TSDB_DATA_TYPE_UBIGINT 14 // 8 bytes
// ----------------- For variable data types such as TSDB_DATA_TYPE_BINARY and TSDB_DATA_TYPE_NCHAR
//typedef int32_t VarDataOffsetT;
//typedef int16_t VarDataLenT; // maxVarDataLen: 32767
//typedef uint16_t TDRowLenT; // not including overhead: 0 ~ 65535
//typedef uint32_t TDRowTLenT; // total length, including overhead
//
//typedef struct tstr {
// VarDataLenT len;
// char data[];
//} tstr;
//
//#pragma pack(push, 1)
//typedef struct {
// VarDataLenT len;
// uint8_t data;
//} SBinaryNullT;
//
//typedef struct {
// VarDataLenT len;
// uint32_t data;
//} SNCharNullT;
//#pragma pack(pop)
//
//#define VARSTR_HEADER_SIZE sizeof(VarDataLenT)
//
//#define varDataLen(v) ((VarDataLenT *)(v))[0]
//#define varDataTLen(v) (sizeof(VarDataLenT) + varDataLen(v))
//#define varDataVal(v) ((void *)((char *)v + VARSTR_HEADER_SIZE))
//#define varDataCopy(dst, v) memcpy((dst), (void*) (v), varDataTLen(v))
//#define varDataLenByData(v) (*(VarDataLenT *)(((char*)(v)) - VARSTR_HEADER_SIZE))
//#define varDataSetLen(v, _len) (((VarDataLenT *)(v))[0] = (VarDataLenT) (_len))
//#define IS_VAR_DATA_TYPE(t) (((t) == TSDB_DATA_TYPE_BINARY) || ((t) == TSDB_DATA_TYPE_NCHAR))
//
//#define varDataNetLen(v) (htons(((VarDataLenT *)(v))[0]))
//#define varDataNetTLen(v) (sizeof(VarDataLenT) + varDataNetLen(v))
#ifdef __cplusplus
}
#endif
......
......@@ -21,7 +21,7 @@ extern "C" {
#endif
#include "os.h"
#include "tdef.h"
//#include "tdef.h"
#include "tarray.h"
#include "tfunctional.h"
......
......@@ -40,9 +40,6 @@ char * paGetToken(char *src, char **token, int32_t *tokenLen);
int32_t taosByteArrayToHexStr(char bytes[], int32_t len, char hexstr[]);
int32_t taosHexStrToByteArray(char hexstr[], char bytes[]);
//bool taosGetVersionNumber(char *versionStr, int *versionNubmer);
//int taosCheckVersion(char *input_client_version, char *input_server_version, int compared_segments);
char * taosIpStr(uint32_t ipInt);
uint32_t ip2uint(const char *const ip_addr);
......
......@@ -418,12 +418,14 @@ static int32_t getDuration(int64_t val, char unit, int64_t* result, int32_t time
return -1;
}
}
/* get the value in microsecond */
return 0;
}
/*
* n - months
* y - Years
* is not allowed, since the duration of month or year are both variable.
*
* b - nanoseconds;
* u - microseconds;
* a - Millionseconds
......@@ -432,8 +434,6 @@ static int32_t getDuration(int64_t val, char unit, int64_t* result, int32_t time
* h - Hours
* d - Days (24 hours)
* w - Weeks (7 days)
* n - Months (30 days)
* y - Years (365 days)
*/
int32_t parseAbsoluteDuration(char* token, int32_t tokenlen, int64_t* duration, char* unit, int32_t timePrecision) {
errno = 0;
......
......@@ -23,12 +23,21 @@
#include "tutil.h"
#include "tvariant.h"
#define SET_EXT_INFO(converted, res, minv, maxv, exti) do { \
if (converted == NULL || exti == NULL || *converted == false) { break; } \
if ((res) < (minv)) { *exti = -1; break; } \
if ((res) > (maxv)) { *exti = 1; break; } \
assert(0); \
} while (0)
#define SET_EXT_INFO(converted, res, minv, maxv, exti) \
do { \
if (converted == NULL || exti == NULL || *converted == false) { \
break; \
} \
if ((res) < (minv)) { \
*exti = -1; \
break; \
} \
if ((res) > (maxv)) { \
*exti = 1; \
break; \
} \
assert(0); \
} while (0)
void taosVariantCreate(SVariant *pVar, char* z, int32_t n, int32_t type) {
int32_t ret = 0;
......@@ -95,7 +104,6 @@ void taosVariantCreate(SVariant *pVar, char* z, int32_t n, int32_t type) {
pVar->nType = type;
}
/**
* create SVariant from binary string, not ascii data
* @param pVar
......@@ -901,7 +909,7 @@ int32_t taosVariantDump(SVariant *pVariant, char *payload, int16_t type, bool in
*
* It is actually the bigint/binary/bool/nchar type transfer
*/
int32_t tVariantTypeSetType(SVariant *pVariant, char type) {
int32_t taosVariantTypeSetType(SVariant *pVariant, char type) {
if (pVariant == NULL || pVariant->nType == 0) { // value is not set
return 0;
}
......
......@@ -14,3 +14,7 @@
*/
#include "catalogInt.h"
struct SCatalog* getCatalogHandle(const SEpSet* pMgmtEps) {
return NULL;
}
......@@ -9,4 +9,6 @@ target_include_directories(
target_link_libraries(
parser
PRIVATE os util common catalog transport
)
\ No newline at end of file
)
ADD_SUBDIRECTORY(test)
......@@ -267,7 +267,7 @@ SRelationInfo *addSubquery(SRelationInfo *pRelationInfo, SArray *pSub, SToken *p
// sql expr leaf node
tSqlExpr *tSqlExprCreateIdValue(SToken *pToken, int32_t optrType);
tSqlExpr *tSqlExprCreateFunction(SArray *pParam, SToken *pFuncToken, SToken *endToken, int32_t optType);
SArray * tAppendFuncName(SArray *pList, SToken *pToken);
SArray * tRecordFuncName(SArray *pList, SToken *pToken);
tSqlExpr *tSqlExprCreate(tSqlExpr *pLeft, tSqlExpr *pRight, int32_t optrType);
tSqlExpr *tSqlExprClone(tSqlExpr *pSrc);
......@@ -299,6 +299,8 @@ SArray *appendSelectClause(SArray *pList, void *pSubclause);
void setCreatedTableName(SSqlInfo *pInfo, SToken *pTableNameToken, SToken *pIfNotExists);
void* destroyCreateTableSql(SCreateTableSql* pCreate);
void setDropFuncInfo(SSqlInfo *pInfo, int32_t type, SToken* pToken);
void setCreateFuncInfo(SSqlInfo *pInfo, int32_t type, SToken *pName, SToken *pPath, SField *output, SToken* bufSize, int32_t funcType);
void SqlInfoDestroy(SSqlInfo *pInfo);
......
......@@ -44,7 +44,7 @@ typedef struct SInsertStmtInfo {
* @param msg
* @return
*/
int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pSqlInfo, SQueryStmtInfo* pQueryInfo, int64_t id, char* msg);
int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pSqlInfo, SQueryStmtInfo* pQueryInfo, int64_t id, char* msg, int32_t msgLen);
/**
*
......@@ -52,7 +52,7 @@ int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pSqlInfo, SQ
* @param pMetaInfo
* @return
*/
int32_t qParserExtractRequestedMetaInfo(const struct SSqlNode* pSqlNode, SMetaReq* pMetaInfo);
int32_t qParserExtractRequestedMetaInfo(const SArray* pSqlNodeList, SMetaReq* pMetaInfo);
#ifdef __cplusplus
}
......
......@@ -20,6 +20,10 @@
extern "C" {
#endif
#include "os.h"
#include "ttoken.h"
int32_t parserValidateNameToken(SToken* pToken);
#ifdef __cplusplus
}
......
......@@ -325,7 +325,7 @@ alter_db_optr(Y) ::= alter_db_optr(Z) cachelast(X). { Y = Z; Y.cachelast = str
alter_topic_optr(Y) ::= alter_db_optr(Z). { Y = Z; Y.dbType = TSDB_DB_TYPE_TOPIC; }
alter_topic_optr(Y) ::= alter_topic_optr(Z) partitions(X). { Y = Z; Y.partitions = strtol(X.z, NULL, 10); }
%type typename {TAOS_FIELD}
%type typename {SField}
typename(A) ::= ids(X). {
X.type = 0;
tSetColumnType (&A, &X);
......@@ -425,11 +425,11 @@ create_table_args(A) ::= ifnotexists(U) ids(V) cpxName(Z) AS select(S). {
setCreatedTableName(pInfo, &V, &U);
}
%type column{TAOS_FIELD}
%type column{SField}
%type columnlist{SArray*}
%destructor columnlist {taosArrayDestroy($$);}
columnlist(A) ::= columnlist(X) COMMA column(Y). {taosArrayPush(X, &Y); A = X; }
columnlist(A) ::= column(X). {A = taosArrayInit(4, sizeof(TAOS_FIELD)); taosArrayPush(A, &X);}
columnlist(A) ::= column(X). {A = taosArrayInit(4, sizeof(SField)); taosArrayPush(A, &X);}
// The information used for a column is the name and type of column:
// tinyint smallint int bigint float double bool timestamp binary(x) nchar(x)
......@@ -601,7 +601,7 @@ fill_opt(N) ::= FILL LP ID(Y) COMMA tagitemlist(X) RP. {
toTSDBType(Y.type);
taosVariantCreate(&A, Y.z, Y.n, Y.type);
tVariantListInsert(X, &A, -1, 0);
tListItemInsert(X, &A, -1, 0);
N = X;
}
......@@ -719,10 +719,10 @@ expr(A) ::= BOOL(X). { A = tSqlExprCreateIdValue(&X, TK_BOOL);}
expr(A) ::= NULL(X). { A = tSqlExprCreateIdValue(&X, TK_NULL);}
// ordinary functions: min(x), max(x), top(k, 20)
expr(A) ::= ID(X) LP exprlist(Y) RP(E). { tAppendFuncName(pInfo->funcs, &X); A = tSqlExprCreateFunction(Y, &X, &E, X.type); }
expr(A) ::= ID(X) LP exprlist(Y) RP(E). { tRecordFuncName(pInfo->funcs, &X); A = tSqlExprCreateFunction(Y, &X, &E, X.type); }
// for parsing sql functions with wildcard for parameters. e.g., count(*)/first(*)/last(*) operation
expr(A) ::= ID(X) LP STAR RP(Y). { tAppendFuncName(pInfo->funcs, &X); A = tSqlExprCreateFunction(NULL, &X, &Y, X.type); }
expr(A) ::= ID(X) LP STAR RP(Y). { tRecordFuncName(pInfo->funcs, &X); A = tSqlExprCreateFunction(NULL, &X, &Y, X.type); }
// is (not) null expression
expr(A) ::= expr(X) IS NULL. {A = tSqlExprCreate(X, NULL, TK_ISNULL);}
......
......@@ -252,7 +252,7 @@ tSqlExpr *tSqlExprCreateFunction(SArray *pParam, SToken *pFuncToken, SToken *end
return pExpr;
}
SArray *tAppendFuncName(SArray *pList, SToken *pToken) {
SArray *tRecordFuncName(SArray *pList, SToken *pToken) {
assert(pList != NULL && pToken != NULL);
taosArrayPush(pList, pToken);
return pList;
......@@ -286,7 +286,6 @@ tSqlExpr *tSqlExprCreate(tSqlExpr *pLeft, tSqlExpr *pRight, int32_t optrType) {
pExpr->value.i64 = pLeft->value.i64 + pRight->value.i64;
break;
}
case TK_MINUS: {
pExpr->value.i64 = pLeft->value.i64 - pRight->value.i64;
break;
......@@ -681,6 +680,7 @@ SAlterTableInfo *tSetAlterTableInfo(SToken *pTableName, SArray *pCols, SArray *p
return pAlterTable;
}
SCreatedTableInfo createNewChildTableInfo(SToken *pTableName, SArray *pTagNames, SArray *pTagVals, SToken *pToken, SToken* igExists) {
SCreatedTableInfo info;
memset(&info, 0, sizeof(SCreatedTableInfo));
......@@ -762,6 +762,7 @@ SSqlInfo* setSqlInfo(SSqlInfo *pInfo, void *pSqlExprInfo, SToken *pTableName, in
return pInfo;
}
SArray* setSubclause(SArray* pList, void *pSqlNode) {
if (pList == NULL) {
pList = taosArrayInit(1, POINTER_BYTES);
......@@ -770,6 +771,7 @@ SArray* setSubclause(SArray* pList, void *pSqlNode) {
taosArrayPush(pList, &pSqlNode);
return pList;
}
SArray* appendSelectClause(SArray *pList, void *pSubclause) {
taosArrayPush(pList, &pSubclause);
return pList;
......@@ -792,6 +794,34 @@ void* destroyCreateTableSql(SCreateTableSql* pCreate) {
return NULL;
}
void setDropFuncInfo(SSqlInfo *pInfo, int32_t type, SToken* pToken) {
pInfo->type = type;
if (pInfo->pMiscInfo == NULL) {
pInfo->pMiscInfo = (SMiscInfo *)calloc(1, sizeof(SMiscInfo));
pInfo->pMiscInfo->a = taosArrayInit(4, sizeof(SToken));
}
taosArrayPush(pInfo->pMiscInfo->a, pToken);
}
void setCreateFuncInfo(SSqlInfo *pInfo, int32_t type, SToken *pName, SToken *pPath, SField *output, SToken* bufSize, int32_t funcType) {
pInfo->type = type;
if (pInfo->pMiscInfo == NULL) {
pInfo->pMiscInfo = calloc(1, sizeof(SMiscInfo));
}
pInfo->pMiscInfo->funcOpt.name = *pName;
pInfo->pMiscInfo->funcOpt.path = *pPath;
pInfo->pMiscInfo->funcOpt.output = *output;
pInfo->pMiscInfo->funcOpt.type = funcType;
if (bufSize->n > 0) {
pInfo->pMiscInfo->funcOpt.bufSize = strtol(bufSize->z, NULL, 10);
} else {
pInfo->pMiscInfo->funcOpt.bufSize = 0;
}
}
void SqlInfoDestroy(SSqlInfo *pInfo) {
if (pInfo == NULL) return;;
taosArrayDestroy(pInfo->funcs);
......@@ -840,6 +870,7 @@ void setDCLSqlElems(SSqlInfo *pInfo, int32_t type, int32_t nParam, ...) {
va_end(va);
}
void setDropDbTableInfo(SSqlInfo *pInfo, int32_t type, SToken* pToken, SToken* existsCheck, int16_t dbType, int16_t tableType) {
pInfo->type = type;
......@@ -854,6 +885,7 @@ void setDropDbTableInfo(SSqlInfo *pInfo, int32_t type, SToken* pToken, SToken* e
pInfo->pMiscInfo->dbType = dbType;
pInfo->pMiscInfo->tableType = tableType;
}
void setShowOptions(SSqlInfo *pInfo, int32_t type, SToken* prefix, SToken* pPatterns) {
if (pInfo->pMiscInfo == NULL) {
pInfo->pMiscInfo = calloc(1, sizeof(SMiscInfo));
......@@ -903,6 +935,7 @@ void setCreateAcctSql(SSqlInfo *pInfo, int32_t type, SToken *pName, SToken *pPwd
pInfo->pMiscInfo->user.passwd = *pPwd;
}
}
void setCreateUserSql(SSqlInfo *pInfo, SToken *pName, SToken *pPasswd) {
pInfo->type = TSDB_SQL_CREATE_USER;
if (pInfo->pMiscInfo == NULL) {
......@@ -914,6 +947,7 @@ void setCreateUserSql(SSqlInfo *pInfo, SToken *pName, SToken *pPasswd) {
pInfo->pMiscInfo->user.user = *pName;
pInfo->pMiscInfo->user.passwd = *pPasswd;
}
void setKillSql(SSqlInfo *pInfo, int32_t type, SToken *id) {
pInfo->type = type;
if (pInfo->pMiscInfo == NULL) {
......@@ -980,7 +1014,13 @@ void setDefaultCreateDbOption(SCreateDbInfo *pDBInfo) {
memset(&pDBInfo->precision, 0, sizeof(SToken));
}
void setDefaultCreateTopicOption(SCreateDbInfo *pDBInfo);
void setDefaultCreateTopicOption(SCreateDbInfo *pDBInfo) {
setDefaultCreateDbOption(pDBInfo);
pDBInfo->dbType = TSDB_DB_TYPE_TOPIC;
pDBInfo->partitions = TSDB_DEFAULT_DB_PARTITON_OPTION;
}
// prefix show db.tables;
void tSetDbName(SToken *pCpxName, SToken *pDb) {
......
......@@ -13,14 +13,459 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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;
}
int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQueryStmtInfo* pQueryInfo, int64_t id, char* msg) {
int32_t qParserValidateSqlNode(struct SCatalog* pCatalog, SSqlInfo* pInfo, SQueryStmtInfo* pQueryInfo, int64_t id, char* msgBuf, int32_t msgBufLen) {
//1. if it is a query, get the meta info and continue.
assert(pCatalog != NULL && pInfo != NULL);
int32_t code = 0;
#if 0
switch (pInfo->type) {
case TSDB_SQL_DROP_TABLE:
case TSDB_SQL_DROP_USER:
case TSDB_SQL_DROP_ACCT:
case TSDB_SQL_DROP_DNODE:
case TSDB_SQL_DROP_DB: {
const char* msg1 = "param name too long";
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_DB) {
assert(taosArrayGetSize(pInfo->pMiscInfo->a) == 1);
code = tNameSetDbName(&pTableMetaInfo->name, getAccountId(pSql), pzName);
if (code != TSDB_CODE_SUCCESS) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg2);
}
} else if (pInfo->type == TSDB_SQL_DROP_TABLE) {
assert(taosArrayGetSize(pInfo->pMiscInfo->a) == 1);
code = tscSetTableFullName(&pTableMetaInfo->name, pzName, pSql);
if(code != TSDB_CODE_SUCCESS) {
return code;
}
} else if (pInfo->type == TSDB_SQL_DROP_DNODE) {
if (pzName->type == TK_STRING) {
pzName->n = strdequote(pzName->z);
}
strncpy(pCmd->payload, pzName->z, pzName->n);
} else { // drop user/account
if (pzName->n >= TSDB_USER_LEN) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg3);
}
strncpy(pCmd->payload, pzName->z, pzName->n);
}
break;
}
case TSDB_SQL_USE_DB: {
const char* msg = "invalid db name";
SToken* pToken = taosArrayGet(pInfo->pMiscInfo->a, 0);
if (tscValidateName(pToken) != TSDB_CODE_SUCCESS) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg);
}
int32_t ret = tNameSetDbName(&pTableMetaInfo->name, getAccountId(pSql), pToken);
if (ret != TSDB_CODE_SUCCESS) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg);
}
break;
}
case TSDB_SQL_RESET_CACHE: {
return TSDB_CODE_SUCCESS;
}
case TSDB_SQL_SHOW: {
if (setShowInfo(pSql, pInfo) != TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
break;
}
case TSDB_SQL_CREATE_FUNCTION:
case TSDB_SQL_DROP_FUNCTION: {
code = handleUserDefinedFunc(pSql, pInfo);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
break;
}
case TSDB_SQL_ALTER_DB:
case TSDB_SQL_CREATE_DB: {
const char* msg1 = "invalid db name";
const char* msg2 = "name too long";
SCreateDbInfo* pCreateDB = &(pInfo->pMiscInfo->dbOpt);
if (pCreateDB->dbname.n >= TSDB_DB_NAME_LEN) {
return setInvalidOperatorErrMsg(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);
}
int32_t ret = tNameSetDbName(&pTableMetaInfo->name, getAccountId(pSql), &token);
if (ret != TSDB_CODE_SUCCESS) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg2);
}
if (parseCreateDBOptions(pCmd, pCreateDB) != TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
break;
}
case TSDB_SQL_CREATE_DNODE: {
const char* msg = "invalid host name (ip address)";
if (taosArrayGetSize(pInfo->pMiscInfo->a) > 1) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg);
}
SToken* id = taosArrayGet(pInfo->pMiscInfo->a, 0);
if (id->type == TK_STRING) {
id->n = strdequote(id->z);
}
break;
}
case TSDB_SQL_CREATE_ACCT:
case TSDB_SQL_ALTER_ACCT: {
const char* msg1 = "invalid state option, available options[no, r, w, all]";
const char* msg2 = "invalid user/account name";
const char* msg3 = "name too long";
SToken* pName = &pInfo->pMiscInfo->user.user;
SToken* pPwd = &pInfo->pMiscInfo->user.passwd;
if (handlePassword(pCmd, pPwd) != TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
if (pName->n >= TSDB_USER_LEN) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg3);
}
if (tscValidateName(pName) != TSDB_CODE_SUCCESS) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg2);
}
SCreateAcctInfo* pAcctOpt = &pInfo->pMiscInfo->acctOpt;
if (pAcctOpt->stat.n > 0) {
if (pAcctOpt->stat.z[0] == 'r' && pAcctOpt->stat.n == 1) {
} else if (pAcctOpt->stat.z[0] == 'w' && pAcctOpt->stat.n == 1) {
} 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);
}
}
break;
}
case TSDB_SQL_DESCRIBE_TABLE: {
const char* msg1 = "invalid table name";
SToken* pToken = taosArrayGet(pInfo->pMiscInfo->a, 0);
if (tscValidateName(pToken) != TSDB_CODE_SUCCESS) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg1);
}
// additional msg has been attached already
code = tscSetTableFullName(&pTableMetaInfo->name, pToken, pSql);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
return tscGetTableMeta(pSql, pTableMetaInfo);
}
case TSDB_SQL_SHOW_CREATE_STABLE:
case TSDB_SQL_SHOW_CREATE_TABLE: {
const char* msg1 = "invalid table name";
SToken* pToken = taosArrayGet(pInfo->pMiscInfo->a, 0);
if (tscValidateName(pToken) != TSDB_CODE_SUCCESS) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg1);
}
code = tscSetTableFullName(&pTableMetaInfo->name, pToken, pSql);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
return tscGetTableMeta(pSql, pTableMetaInfo);
}
case TSDB_SQL_SHOW_CREATE_DATABASE: {
const char* msg1 = "invalid database name";
SToken* pToken = taosArrayGet(pInfo->pMiscInfo->a, 0);
if (tscValidateName(pToken) != TSDB_CODE_SUCCESS) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg1);
}
if (pToken->n > TSDB_DB_NAME_LEN) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg1);
}
return tNameSetDbName(&pTableMetaInfo->name, getAccountId(pSql), pToken);
}
case TSDB_SQL_CFG_DNODE: {
const char* msg2 = "invalid configure options or values, such as resetlog / debugFlag 135 / balance 'vnode:2-dnode:2' / monitor 1 ";
const char* msg3 = "invalid dnode ep";
/* validate the ip address */
SMiscInfo* pMiscInfo = pInfo->pMiscInfo;
/* validate the parameter names and options */
if (validateDNodeConfig(pMiscInfo) != TSDB_CODE_SUCCESS) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg2);
}
char* pMsg = pCmd->payload;
SCfgDnodeMsg* pCfg = (SCfgDnodeMsg*)pMsg;
SToken* t0 = taosArrayGet(pMiscInfo->a, 0);
SToken* t1 = taosArrayGet(pMiscInfo->a, 1);
t0->n = strdequote(t0->z);
strncpy(pCfg->ep, t0->z, t0->n);
if (validateEp(pCfg->ep) != TSDB_CODE_SUCCESS) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg3);
}
strncpy(pCfg->config, t1->z, t1->n);
if (taosArrayGetSize(pMiscInfo->a) == 3) {
SToken* t2 = taosArrayGet(pMiscInfo->a, 2);
pCfg->config[t1->n] = ' '; // add sep
strncpy(&pCfg->config[t1->n + 1], t2->z, t2->n);
}
break;
}
case TSDB_SQL_CREATE_USER:
case TSDB_SQL_ALTER_USER: {
const char* msg2 = "invalid user/account name";
const char* msg3 = "name too long";
const char* msg5 = "invalid user rights";
const char* msg7 = "not support options";
pCmd->command = pInfo->type;
SUserInfo* pUser = &pInfo->pMiscInfo->user;
SToken* pName = &pUser->user;
SToken* pPwd = &pUser->passwd;
if (pName->n >= TSDB_USER_LEN) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg3);
}
if (tscValidateName(pName) != TSDB_CODE_SUCCESS) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg2);
}
if (pCmd->command == TSDB_SQL_CREATE_USER) {
if (handlePassword(pCmd, pPwd) != TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
} else {
if (pUser->type == TSDB_ALTER_USER_PASSWD) {
if (handlePassword(pCmd, pPwd) != TSDB_CODE_SUCCESS) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
} else if (pUser->type == TSDB_ALTER_USER_PRIVILEGES) {
assert(pPwd->type == TSDB_DATA_TYPE_NULL);
SToken* pPrivilege = &pUser->privilege;
if (strncasecmp(pPrivilege->z, "super", 5) == 0 && pPrivilege->n == 5) {
pCmd->count = 1;
} else if (strncasecmp(pPrivilege->z, "read", 4) == 0 && pPrivilege->n == 4) {
pCmd->count = 2;
} else if (strncasecmp(pPrivilege->z, "write", 5) == 0 && pPrivilege->n == 5) {
pCmd->count = 3;
} else {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg5);
}
} else {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg7);
}
}
break;
}
case TSDB_SQL_CFG_LOCAL: {
SMiscInfo *pMiscInfo = pInfo->pMiscInfo;
const char *msg = "invalid configure options or values";
// validate the parameter names and options
if (validateLocalConfig(pMiscInfo) != TSDB_CODE_SUCCESS) {
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, msg);
}
int32_t numOfToken = (int32_t) taosArrayGetSize(pMiscInfo->a);
assert(numOfToken >= 1 && numOfToken <= 2);
SToken* t = taosArrayGet(pMiscInfo->a, 0);
strncpy(pCmd->payload, t->z, t->n);
if (numOfToken == 2) {
SToken* t1 = taosArrayGet(pMiscInfo->a, 1);
pCmd->payload[t->n] = ' '; // add sep
strncpy(&pCmd->payload[t->n + 1], t1->z, t1->n);
}
return TSDB_CODE_SUCCESS;
}
case TSDB_SQL_CREATE_TABLE: {
SCreateTableSql* pCreateTable = pInfo->pCreateTableInfo;
if (pCreateTable->type == TSQL_CREATE_TABLE || pCreateTable->type == TSQL_CREATE_STABLE) {
if ((code = doCheckForCreateTable(pSql, 0, pInfo)) != TSDB_CODE_SUCCESS) {
return code;
}
} else if (pCreateTable->type == TSQL_CREATE_TABLE_FROM_STABLE) {
assert(pCmd->numOfCols == 0);
if ((code = doCheckForCreateFromStable(pSql, pInfo)) != TSDB_CODE_SUCCESS) {
return code;
}
} else if (pCreateTable->type == TSQL_CREATE_STREAM) {
if ((code = doCheckForStream(pSql, pInfo)) != TSDB_CODE_SUCCESS) {
return code;
}
}
break;
}
case TSDB_SQL_SELECT: {
const char * msg1 = "no nested query supported in union clause";
code = loadAllTableMeta(pSql, pInfo);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
pQueryInfo = tscGetQueryInfo(pCmd);
size_t size = taosArrayGetSize(pInfo->list);
for (int32_t i = 0; i < size; ++i) {
SSqlNode* pSqlNode = taosArrayGetP(pInfo->list, i);
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);
}
// normalizeSqlNode(pSqlNode); // normalize the column name in each function
if ((code = validateSqlNode(pSql, pSqlNode, pQueryInfo)) != TSDB_CODE_SUCCESS) {
return code;
}
tscPrintSelNodeList(pSql, i);
if ((i + 1) < size && pQueryInfo->sibling == NULL) {
if ((code = tscAddQueryInfo(pCmd)) != TSDB_CODE_SUCCESS) {
return code;
}
SArray *pUdfInfo = NULL;
if (pQueryInfo->pUdfInfo) {
pUdfInfo = taosArrayDup(pQueryInfo->pUdfInfo);
}
pQueryInfo = pCmd->active;
pQueryInfo->pUdfInfo = pUdfInfo;
pQueryInfo->udfCopy = true;
}
}
if ((code = normalizeVarDataTypeLength(pCmd)) != TSDB_CODE_SUCCESS) {
return code;
}
// set the command/global limit parameters from the first subclause to the sqlcmd object
pCmd->active = pCmd->pQueryInfo;
pCmd->command = pCmd->pQueryInfo->command;
STableMetaInfo* pTableMetaInfo1 = tscGetMetaInfo(pCmd->active, 0);
if (pTableMetaInfo1->pTableMeta != NULL) {
pSql->res.precision = tscGetTableInfo(pTableMetaInfo1->pTableMeta).precision;
}
return TSDB_CODE_SUCCESS; // do not build query message here
}
case TSDB_SQL_ALTER_TABLE: {
if ((code = setAlterTableInfo(pSql, pInfo)) != TSDB_CODE_SUCCESS) {
return code;
}
break;
}
case TSDB_SQL_KILL_QUERY:
case TSDB_SQL_KILL_STREAM:
case TSDB_SQL_KILL_CONNECTION: {
if ((code = setKillInfo(pSql, pInfo, pInfo->type)) != TSDB_CODE_SUCCESS) {
return code;
}
break;
}
case TSDB_SQL_SYNC_DB_REPLICA: {
const char* msg1 = "invalid db name";
SToken* pzName = taosArrayGet(pInfo->pMiscInfo->a, 0);
assert(taosArrayGetSize(pInfo->pMiscInfo->a) == 1);
code = tNameSetDbName(&pTableMetaInfo->name, getAccountId(pSql), pzName);
if (code != TSDB_CODE_SUCCESS) {
return setInvalidOperatorErrMsg(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);
}
break;
}
default:
return setInvalidOperatorErrMsg(msgBuf, msgBufLen, "not support sql expression");
}
#endif
SMetaReq req = {0};
qParserExtractRequestedMetaInfo(pInfo->list, &req);
// qParserExtractRequestedMetaInfo(pInfo->)
return 0;
}
......@@ -24,17 +24,17 @@ bool qIsInsertSql(const char* pStr, size_t length) {
int32_t qParseQuerySql(const char* pStr, size_t length, struct SQueryStmtInfo** pQueryInfo, int64_t id, char* msg, int32_t msgLen) {
*pQueryInfo = calloc(1, sizeof(SQueryStmtInfo));
if (*pQueryInfo == NULL) {
return -1; // set correct error code.
return TSDB_CODE_TSC_OUT_OF_MEMORY; // set correct error code.
}
SSqlInfo info = doGenerateAST(pStr);
if (!info.valid) {
strcpy(msg, info.msg);
return -1; // set correct error code.
strncpy(msg, info.msg, msgLen);
return TSDB_CODE_TSC_SQL_SYNTAX_ERROR;
}
struct SCatalog* pCatalog = getCatalogHandle(NULL);
int32_t code = qParserValidateSqlNode(pCatalog, &info, *pQueryInfo, id, msg);
int32_t code = qParserValidateSqlNode(pCatalog, &info, *pQueryInfo, id, msg, msgLen);
if (code != 0) {
return code;
}
......@@ -50,6 +50,6 @@ int32_t qParserConvertSql(const char* pStr, size_t length, char** pConvertSql) {
return 0;
}
int32_t qParserExtractRequestedMetaInfo(const struct SSqlNode* pSqlNode, SMetaReq* pMetaInfo) {
int32_t qParserExtractRequestedMetaInfo(const SArray* pSqlNodeList, SMetaReq* pMetaInfo) {
return 0;
}
\ No newline at end of file
......@@ -108,13 +108,13 @@ typedef union {
int yy130;
SArray* yy135;
SIntervalVal yy160;
TAOS_FIELD yy181;
SVariant yy191;
SLimit yy247;
SCreateDbInfo yy256;
SWindowStateVal yy258;
int32_t yy262;
SCreateAcctInfo yy277;
SField yy304;
SRelationInfo* yy460;
SSqlNode* yy488;
SSessionWindowVal yy511;
......@@ -2431,10 +2431,10 @@ static void yy_reduce(
{ setCreateDbInfo(pInfo, TSDB_SQL_CREATE_DB, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy256, &yymsp[-2].minor.yy0);}
break;
case 62: /* cmd ::= CREATE FUNCTION ids AS ids OUTPUTTYPE typename bufsize */
{ setCreateFuncInfo(pInfo, TSDB_SQL_CREATE_FUNCTION, &yymsp[-5].minor.yy0, &yymsp[-3].minor.yy0, &yymsp[-1].minor.yy181, &yymsp[0].minor.yy0, 1);}
{ setCreateFuncInfo(pInfo, TSDB_SQL_CREATE_FUNCTION, &yymsp[-5].minor.yy0, &yymsp[-3].minor.yy0, &yymsp[-1].minor.yy304, &yymsp[0].minor.yy0, 1);}
break;
case 63: /* cmd ::= CREATE AGGREGATE FUNCTION ids AS ids OUTPUTTYPE typename bufsize */
{ setCreateFuncInfo(pInfo, TSDB_SQL_CREATE_FUNCTION, &yymsp[-5].minor.yy0, &yymsp[-3].minor.yy0, &yymsp[-1].minor.yy181, &yymsp[0].minor.yy0, 2);}
{ setCreateFuncInfo(pInfo, TSDB_SQL_CREATE_FUNCTION, &yymsp[-5].minor.yy0, &yymsp[-3].minor.yy0, &yymsp[-1].minor.yy304, &yymsp[0].minor.yy0, 2);}
break;
case 64: /* cmd ::= CREATE USER ids PASS ids */
{ setCreateUserSql(pInfo, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);}
......@@ -2601,29 +2601,29 @@ static void yy_reduce(
case 133: /* typename ::= ids */
{
yymsp[0].minor.yy0.type = 0;
tSetColumnType (&yylhsminor.yy181, &yymsp[0].minor.yy0);
tSetColumnType (&yylhsminor.yy304, &yymsp[0].minor.yy0);
}
yymsp[0].minor.yy181 = yylhsminor.yy181;
yymsp[0].minor.yy304 = yylhsminor.yy304;
break;
case 134: /* typename ::= ids LP signed RP */
{
if (yymsp[-1].minor.yy531 <= 0) {
yymsp[-3].minor.yy0.type = 0;
tSetColumnType(&yylhsminor.yy181, &yymsp[-3].minor.yy0);
tSetColumnType(&yylhsminor.yy304, &yymsp[-3].minor.yy0);
} else {
yymsp[-3].minor.yy0.type = -yymsp[-1].minor.yy531; // negative value of name length
tSetColumnType(&yylhsminor.yy181, &yymsp[-3].minor.yy0);
tSetColumnType(&yylhsminor.yy304, &yymsp[-3].minor.yy0);
}
}
yymsp[-3].minor.yy181 = yylhsminor.yy181;
yymsp[-3].minor.yy304 = yylhsminor.yy304;
break;
case 135: /* typename ::= ids UNSIGNED */
{
yymsp[-1].minor.yy0.type = 0;
yymsp[-1].minor.yy0.n = ((yymsp[0].minor.yy0.z + yymsp[0].minor.yy0.n) - yymsp[-1].minor.yy0.z);
tSetColumnType (&yylhsminor.yy181, &yymsp[-1].minor.yy0);
tSetColumnType (&yylhsminor.yy304, &yymsp[-1].minor.yy0);
}
yymsp[-1].minor.yy181 = yylhsminor.yy181;
yymsp[-1].minor.yy304 = yylhsminor.yy304;
break;
case 136: /* signed ::= INTEGER */
{ yylhsminor.yy531 = strtol(yymsp[0].minor.yy0.z, NULL, 10); }
......@@ -2711,18 +2711,18 @@ static void yy_reduce(
yymsp[-4].minor.yy110 = yylhsminor.yy110;
break;
case 152: /* columnlist ::= columnlist COMMA column */
{taosArrayPush(yymsp[-2].minor.yy135, &yymsp[0].minor.yy181); yylhsminor.yy135 = yymsp[-2].minor.yy135; }
{taosArrayPush(yymsp[-2].minor.yy135, &yymsp[0].minor.yy304); yylhsminor.yy135 = yymsp[-2].minor.yy135; }
yymsp[-2].minor.yy135 = yylhsminor.yy135;
break;
case 153: /* columnlist ::= column */
{yylhsminor.yy135 = taosArrayInit(4, sizeof(TAOS_FIELD)); taosArrayPush(yylhsminor.yy135, &yymsp[0].minor.yy181);}
{yylhsminor.yy135 = taosArrayInit(4, sizeof(SField)); taosArrayPush(yylhsminor.yy135, &yymsp[0].minor.yy304);}
yymsp[0].minor.yy135 = yylhsminor.yy135;
break;
case 154: /* column ::= ids typename */
{
tSetColumnInfo(&yylhsminor.yy181, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy181);
tSetColumnInfo(&yylhsminor.yy304, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy304);
}
yymsp[-1].minor.yy181 = yylhsminor.yy181;
yymsp[-1].minor.yy304 = yylhsminor.yy304;
break;
case 161: /* tagitem ::= NULL */
{ yymsp[0].minor.yy0.type = 0; taosVariantCreate(&yylhsminor.yy191, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.type); }
......@@ -2893,7 +2893,7 @@ static void yy_reduce(
toTSDBType(yymsp[-3].minor.yy0.type);
taosVariantCreate(&A, yymsp[-3].minor.yy0.z, yymsp[-3].minor.yy0.n, yymsp[-3].minor.yy0.type);
tVariantListInsert(yymsp[-1].minor.yy135, &A, -1, 0);
tListItemInsert(yymsp[-1].minor.yy135, &A, -1, 0);
yymsp[-5].minor.yy135 = yymsp[-1].minor.yy135;
}
break;
......@@ -3049,11 +3049,11 @@ static void yy_reduce(
yymsp[0].minor.yy526 = yylhsminor.yy526;
break;
case 247: /* expr ::= ID LP exprlist RP */
{ tAppendFuncName(pInfo->funcs, &yymsp[-3].minor.yy0); yylhsminor.yy526 = tSqlExprCreateFunction(yymsp[-1].minor.yy135, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0, yymsp[-3].minor.yy0.type); }
{ tRecordFuncName(pInfo->funcs, &yymsp[-3].minor.yy0); yylhsminor.yy526 = tSqlExprCreateFunction(yymsp[-1].minor.yy135, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0, yymsp[-3].minor.yy0.type); }
yymsp[-3].minor.yy526 = yylhsminor.yy526;
break;
case 248: /* expr ::= ID LP STAR RP */
{ tAppendFuncName(pInfo->funcs, &yymsp[-3].minor.yy0); yylhsminor.yy526 = tSqlExprCreateFunction(NULL, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0, yymsp[-3].minor.yy0.type); }
{ tRecordFuncName(pInfo->funcs, &yymsp[-3].minor.yy0); yylhsminor.yy526 = tSqlExprCreateFunction(NULL, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0, yymsp[-3].minor.yy0.type); }
yymsp[-3].minor.yy526 = yylhsminor.yy526;
break;
case 249: /* expr ::= expr IS NULL */
......
......@@ -14,11 +14,7 @@
*/
#include "os.h"
#include "tcrc32c.h"
#include "tdef.h"
#include "tutil.h"
#include "ulog.h"
#include "taoserror.h"
int32_t strdequote(char *z) {
if (z == NULL) {
......@@ -51,7 +47,6 @@ int32_t strdequote(char *z) {
return j + 1; // only one quote, do nothing
}
int32_t strRmquote(char *z, int32_t len){
// delete escape character: \\, \', \"
char delim = z[0];
......@@ -83,7 +78,6 @@ int32_t strRmquote(char *z, int32_t len){
return len - 2 - cnt;
}
size_t strtrim(char *z) {
int32_t i = 0;
int32_t j = 0;
......@@ -164,8 +158,6 @@ char *strnchr(char *haystack, char needle, int32_t len, bool skipquote) {
return NULL;
}
char* strtolower(char *dst, const char *src) {
int esc = 0;
char quote = 0, *p = dst, c;
......@@ -380,66 +372,6 @@ int32_t taosHexStrToByteArray(char hexstr[], char bytes[]) {
return 0;
}
// TODO move to comm module
bool taosGetVersionNumber(char *versionStr, int *versionNubmer) {
if (versionStr == NULL || versionNubmer == NULL) {
return false;
}
int versionNumberPos[5] = {0};
int len = (int)strlen(versionStr);
int dot = 0;
for (int pos = 0; pos < len && dot < 4; ++pos) {
if (versionStr[pos] == '.') {
versionStr[pos] = 0;
versionNumberPos[++dot] = pos + 1;
}
}
if (dot != 3) {
return false;
}
for (int pos = 0; pos < 4; ++pos) {
versionNubmer[pos] = atoi(versionStr + versionNumberPos[pos]);
}
versionStr[versionNumberPos[1] - 1] = '.';
versionStr[versionNumberPos[2] - 1] = '.';
versionStr[versionNumberPos[3] - 1] = '.';
return true;
}
int taosCheckVersion(char *input_client_version, char *input_server_version, int comparedSegments) {
char client_version[TSDB_VERSION_LEN] = {0};
char server_version[TSDB_VERSION_LEN] = {0};
int clientVersionNumber[4] = {0};
int serverVersionNumber[4] = {0};
tstrncpy(client_version, input_client_version, sizeof(client_version));
tstrncpy(server_version, input_server_version, sizeof(server_version));
if (!taosGetVersionNumber(client_version, clientVersionNumber)) {
uError("invalid client version:%s", client_version);
return TSDB_CODE_TSC_INVALID_VERSION;
}
if (!taosGetVersionNumber(server_version, serverVersionNumber)) {
uError("invalid server version:%s", server_version);
return TSDB_CODE_TSC_INVALID_VERSION;
}
for(int32_t i = 0; i < comparedSegments; ++i) {
if (clientVersionNumber[i] != serverVersionNumber[i]) {
uError("the %d-th number of server version:%s not matched with client version:%s", i, server_version,
client_version);
return TSDB_CODE_TSC_INVALID_VERSION;
}
}
return 0;
}
char *taosIpStr(uint32_t ipInt) {
static char ipStrArray[3][30];
static int ipStrIndex = 0;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册