/* * Copyright (c) 2019 TAOS Data, Inc. * * This program is free software: you can use, redistribute, and/or modify * it under the terms of the GNU Affero General Public License, version 3 * or later ("AGPL"), as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include "qSqlparser.h" #include "os.h" #include "taosdef.h" #include "taosmsg.h" #include "tcmdtype.h" #include "tstrbuild.h" #include "ttoken.h" #include "ttokendef.h" #include "tutil.h" SSqlInfo qSqlParse(const char *pStr) { void *pParser = ParseAlloc(malloc); SSqlInfo sqlInfo = {0}; sqlInfo.valid = true; int32_t i = 0; while (1) { SStrToken t0 = {0}; if (pStr[i] == 0) { Parse(pParser, 0, t0, &sqlInfo); goto abort_parse; } t0.n = tGetToken((char *)&pStr[i], &t0.type); t0.z = (char *)(pStr + i); i += t0.n; switch (t0.type) { case TK_SPACE: case TK_COMMENT: { break; } case TK_SEMI: { Parse(pParser, 0, t0, &sqlInfo); goto abort_parse; } case TK_QUESTION: case TK_ILLEGAL: { snprintf(sqlInfo.msg, tListLen(sqlInfo.msg), "unrecognized token: \"%s\"", t0.z); sqlInfo.valid = false; goto abort_parse; } case TK_HEX: case TK_OCT: case TK_BIN:{ snprintf(sqlInfo.msg, tListLen(sqlInfo.msg), "unsupported token: \"%s\"", t0.z); sqlInfo.valid = false; goto abort_parse; } default: Parse(pParser, t0.type, t0, &sqlInfo); if (sqlInfo.valid == false) { goto abort_parse; } } } abort_parse: ParseFree(pParser, free); return sqlInfo; } SArray *tSqlExprListAppend(SArray *pList, tSqlExpr *pNode, SStrToken *pDistinct, SStrToken *pToken) { if (pList == NULL) { pList = taosArrayInit(4, sizeof(tSqlExprItem)); } if (pNode || pToken) { struct tSqlExprItem item = {0}; item.pNode = pNode; item.distinct = (pDistinct != NULL); if (pToken) { // set the as clause item.aliasName = malloc(pToken->n + 1); strncpy(item.aliasName, pToken->z, pToken->n); item.aliasName[pToken->n] = 0; strdequote(item.aliasName); } taosArrayPush(pList, &item); } return pList; } static void freeExprElem(void* item) { tSqlExprItem* exprItem = item; tfree(exprItem->aliasName); tSqlExprDestroy(exprItem->pNode); } void tSqlExprListDestroy(SArray *pList) { if (pList == NULL) { return; } taosArrayDestroyEx(pList, freeExprElem); } tSqlExpr *tSqlExprCreateIdValue(SStrToken *pToken, int32_t optrType) { tSqlExpr *pSqlExpr = calloc(1, sizeof(tSqlExpr)); if (pToken != NULL) { pSqlExpr->token = *pToken; } if (optrType == TK_NULL) { pToken->type = TSDB_DATA_TYPE_NULL; tVariantCreate(&pSqlExpr->value, pToken); pSqlExpr->tokenId = optrType; pSqlExpr->type = SQL_NODE_VALUE; } else if (optrType == TK_INTEGER || optrType == TK_STRING || optrType == TK_FLOAT || optrType == TK_BOOL) { toTSDBType(pToken->type); tVariantCreate(&pSqlExpr->value, pToken); pSqlExpr->tokenId = optrType; pSqlExpr->type = SQL_NODE_VALUE; } else if (optrType == TK_NOW) { // use microsecond by default pSqlExpr->value.i64 = taosGetTimestamp(TSDB_TIME_PRECISION_MICRO); 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_US_TIMESTAMP; } else if (optrType == TK_VARIABLE) { int32_t ret = parseAbsoluteDuration(pToken->z, pToken->n, &pSqlExpr->value.i64); if (ret != TSDB_CODE_SUCCESS) { terrno = TSDB_CODE_TSC_SQL_SYNTAX_ERROR; } pSqlExpr->flags |= 1 << EXPR_FLAG_US_TIMESTAMP; pSqlExpr->flags |= 1 << EXPR_FLAG_TIMESTAMP_VAR; pSqlExpr->value.nType = TSDB_DATA_TYPE_BIGINT; pSqlExpr->tokenId = TK_TIMESTAMP; pSqlExpr->type = SQL_NODE_VALUE; } else { // Here it must be the column name (tk_id) if it is not a number or string. assert(optrType == TK_ID || optrType == TK_ALL); if (pToken != NULL) { pSqlExpr->colInfo = *pToken; } pSqlExpr->tokenId = optrType; pSqlExpr->type = SQL_NODE_TABLE_COLUMN; } return pSqlExpr; } /* * pList is the parameters for function with id(optType) * function name is denoted by pFunctionToken */ tSqlExpr *tSqlExprCreateFunction(SArray *pParam, SStrToken *pFuncToken, SStrToken *endToken, int32_t optType) { if (pFuncToken == NULL) { return NULL; } tSqlExpr *pExpr = calloc(1, sizeof(tSqlExpr)); pExpr->tokenId = optType; pExpr->type = SQL_NODE_SQLFUNCTION; pExpr->pParam = pParam; int32_t len = (int32_t)((endToken->z + endToken->n) - pFuncToken->z); pExpr->operand = (*pFuncToken); pExpr->token.n = len; pExpr->token.z = pFuncToken->z; pExpr->token.type = pFuncToken->type; return pExpr; } /* * create binary expression in this procedure * if the expr is arithmetic, calculate the result and set it to tSqlExpr Object */ tSqlExpr *tSqlExprCreate(tSqlExpr *pLeft, tSqlExpr *pRight, int32_t optrType) { tSqlExpr *pExpr = calloc(1, sizeof(tSqlExpr)); pExpr->type = SQL_NODE_EXPR; if (pLeft != NULL && pRight != NULL && (optrType != TK_IN)) { char* endPos = pRight->token.z + pRight->token.n; pExpr->token.z = pLeft->token.z; pExpr->token.n = (uint32_t)(endPos - pExpr->token.z); pExpr->token.type = pLeft->token.type; } if ((pLeft != NULL && pRight != NULL) && (optrType == TK_PLUS || optrType == TK_MINUS || optrType == TK_STAR || optrType == TK_DIVIDE || optrType == TK_REM)) { /* * if a token 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; pExpr->flags = pLeft->flags | pRight->flags; if ((pLeft->flags & (1 << EXPR_FLAG_TIMESTAMP_VAR)) && (pRight->flags & (1 << EXPR_FLAG_TIMESTAMP_VAR))) { pExpr->flags |= 1 << EXPR_FLAG_TS_ERROR; } else { pExpr->flags &= ~(1 << EXPR_FLAG_TIMESTAMP_VAR); pExpr->flags &= ~(1 << EXPR_FLAG_TS_ERROR); } 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.dKey = (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.dKey : pLeft->value.i64; double right = (pRight->value.nType == TSDB_DATA_TYPE_DOUBLE) ? pRight->value.dKey : pRight->value.i64; switch (optrType) { case TK_PLUS: { pExpr->value.dKey = left + right; break; } case TK_MINUS: { pExpr->value.dKey = left - right; break; } case TK_STAR: { pExpr->value.dKey = left * right; break; } case TK_DIVIDE: { pExpr->value.dKey = left / right; break; } case TK_REM: { pExpr->value.dKey = 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) { pExpr->tokenId = optrType; pExpr->pLeft = pLeft; tSqlExpr *pRSub = calloc(1, sizeof(tSqlExpr)); pRSub->tokenId = TK_SET; // TODO refactor ..... pRSub->pParam = (SArray *)pRight; pExpr->pRight = pRSub; } else { pExpr->tokenId = optrType; pExpr->pLeft = pLeft; if (pLeft != NULL && pRight == NULL) { pRight = calloc(1, sizeof(tSqlExpr)); } pExpr->pRight = pRight; } return pExpr; } static FORCE_INLINE int32_t tStrTokenCompare(SStrToken* left, SStrToken* right) { return (left->type == right->type && left->n == right->n && strncasecmp(left->z, right->z, left->n) == 0) ? 0 : 1; } int32_t tSqlExprCompare(tSqlExpr *left, tSqlExpr *right) { if ((left == NULL && right) || (left && right == NULL)) { return 1; } if (left->type != right->type) { return 1; } if (left->tokenId != right->tokenId) { return 1; } if (left->functionId != right->functionId) { return 1; } if ((left->pLeft && right->pLeft == NULL) || (left->pLeft == NULL && right->pLeft) || (left->pRight && right->pRight == NULL) || (left->pRight == NULL && right->pRight) || (left->pParam && right->pParam == NULL) || (left->pParam == NULL && right->pParam)) { return 1; } if (tVariantCompare(&left->value, &right->value)) { return 1; } if (tStrTokenCompare(&left->colInfo, &right->colInfo)) { return 1; } if (right->pParam && left->pParam) { size_t size = taosArrayGetSize(right->pParam); if (left->pParam && taosArrayGetSize(left->pParam) != size) { return 1; } for (int32_t i = 0; i < size; i++) { tSqlExprItem* pLeftElem = taosArrayGet(left->pParam, i); tSqlExpr* pSubLeft = pLeftElem->pNode; tSqlExprItem* pRightElem = taosArrayGet(right->pParam, i); tSqlExpr* pSubRight = pRightElem->pNode; if (tSqlExprCompare(pSubLeft, pSubRight)) { return 1; } } } if (left->pLeft && tSqlExprCompare(left->pLeft, right->pLeft)) { return 1; } if (left->pRight && tSqlExprCompare(left->pRight, right->pRight)) { return 1; } return 0; } tSqlExpr *tSqlExprClone(tSqlExpr *pSrc) { tSqlExpr *pExpr = calloc(1, sizeof(tSqlExpr)); memcpy(pExpr, pSrc, sizeof(*pSrc)); if (pSrc->pLeft) { pExpr->pLeft = tSqlExprClone(pSrc->pLeft); } if (pSrc->pRight) { pExpr->pRight = tSqlExprClone(pSrc->pRight); } //we don't clone pParam now because clone is only used for between/and assert(pSrc->pParam == NULL); return pExpr; } void tSqlExprCompact(tSqlExpr** pExpr) { if (*pExpr == NULL || tSqlExprIsParentOfLeaf(*pExpr)) { return; } if ((*pExpr)->pLeft) { tSqlExprCompact(&(*pExpr)->pLeft); } if ((*pExpr)->pRight) { tSqlExprCompact(&(*pExpr)->pRight); } if ((*pExpr)->pLeft == NULL && (*pExpr)->pRight == NULL && ((*pExpr)->tokenId == TK_OR || (*pExpr)->tokenId == TK_AND)) { tSqlExprDestroy(*pExpr); *pExpr = NULL; } else if ((*pExpr)->pLeft == NULL && (*pExpr)->pRight != NULL) { tSqlExpr* tmpPtr = (*pExpr)->pRight; (*pExpr)->pRight = NULL; tSqlExprDestroy(*pExpr); (*pExpr) = tmpPtr; } else if ((*pExpr)->pRight == NULL && (*pExpr)->pLeft != NULL) { tSqlExpr* tmpPtr = (*pExpr)->pLeft; (*pExpr)->pLeft = NULL; tSqlExprDestroy(*pExpr); (*pExpr) = tmpPtr; } } bool tSqlExprIsLeaf(tSqlExpr* pExpr) { return (pExpr->pRight == NULL && pExpr->pLeft == NULL) && (pExpr->tokenId == 0 || (pExpr->tokenId == TK_ID) || (pExpr->tokenId >= TK_BOOL && pExpr->tokenId <= TK_NCHAR) || (pExpr->tokenId == TK_NULL) || (pExpr->tokenId == TK_SET)); } bool tSqlExprIsParentOfLeaf(tSqlExpr* pExpr) { return (pExpr->pLeft != NULL && pExpr->pRight != NULL) && (tSqlExprIsLeaf(pExpr->pLeft) && tSqlExprIsLeaf(pExpr->pRight)); } static void doDestroySqlExprNode(tSqlExpr *pExpr) { if (pExpr == NULL) { return; } if (pExpr->tokenId == TK_STRING) { tVariantDestroy(&pExpr->value); } tSqlExprListDestroy(pExpr->pParam); free(pExpr); } void tSqlExprDestroy(tSqlExpr *pExpr) { if (pExpr == NULL) { return; } tSqlExprDestroy(pExpr->pLeft); pExpr->pLeft = NULL; tSqlExprDestroy(pExpr->pRight); pExpr->pRight = NULL; doDestroySqlExprNode(pExpr); } SArray *tVariantListAppendToken(SArray *pList, SStrToken *pToken, uint8_t order) { if (pList == NULL) { pList = taosArrayInit(4, sizeof(tVariantListItem)); } if (pToken) { tVariantListItem item; tVariantCreate(&item.pVar, pToken); item.sortOrder = order; taosArrayPush(pList, &item); } return pList; } SArray *tVariantListAppend(SArray *pList, tVariant *pVar, uint8_t sortOrder) { if (pList == NULL) { pList = taosArrayInit(4, sizeof(tVariantListItem)); } if (pVar == NULL) { return pList; } /* * Here we do not employ the assign function, since we need the pz attribute of structure * , which is the point to char string, to free it! * * Otherwise, the original pointer may be lost, which causes memory leak. */ tVariantListItem item; item.pVar = *pVar; item.sortOrder = sortOrder; taosArrayPush(pList, &item); return pList; } SArray *tVariantListInsert(SArray *pList, tVariant *pVar, uint8_t sortOrder, int32_t index) { if (pList == NULL || pVar == NULL || index >= taosArrayGetSize(pList)) { return tVariantListAppend(NULL, pVar, sortOrder); } tVariantListItem item; item.pVar = *pVar; item.sortOrder = sortOrder; taosArrayInsert(pList, index, &item); return pList; } SRelationInfo *setTableNameList(SRelationInfo* pRelationInfo, SStrToken *pName, SStrToken* pAlias) { if (pRelationInfo == NULL) { pRelationInfo = calloc(1, sizeof(SRelationInfo)); pRelationInfo->list = taosArrayInit(4, sizeof(STableNamePair)); } pRelationInfo->type = SQL_NODE_FROM_TABLELIST; STableNamePair p = {.name = *pName}; if (pAlias != NULL) { p.aliasName = *pAlias; } else { TPARSER_SET_NONE_TOKEN(p.aliasName); } taosArrayPush(pRelationInfo->list, &p); return pRelationInfo; } SRelationInfo* setSubquery(SRelationInfo* pRelationInfo, SArray* pList) { if (pRelationInfo == NULL) { pRelationInfo = calloc(1, sizeof(SRelationInfo)); pRelationInfo->list = taosArrayInit(4, POINTER_BYTES); } pRelationInfo->type = SQL_NODE_FROM_SUBQUERY; taosArrayPush(pRelationInfo->list, &pList); return pRelationInfo; } void* destroyRelationInfo(SRelationInfo* pRelationInfo) { if (pRelationInfo == NULL) { return NULL; } if (pRelationInfo->type == SQL_NODE_FROM_TABLELIST) { taosArrayDestroy(pRelationInfo->list); } else { size_t size = taosArrayGetSize(pRelationInfo->list); for(int32_t i = 0; i < size; ++i) { SArray* pa = taosArrayGetP(pRelationInfo->list, 0); destroyAllSqlNode(pa); } taosArrayDestroy(pRelationInfo->list); } tfree(pRelationInfo); return NULL; } void tSetDbName(SStrToken *pCpxName, SStrToken *pDb) { pCpxName->type = pDb->type; pCpxName->z = pDb->z; pCpxName->n = pDb->n; } void tSetColumnInfo(TAOS_FIELD *pField, SStrToken *pName, TAOS_FIELD *pType) { int32_t maxLen = sizeof(pField->name) / sizeof(pField->name[0]); // column name is too long, set the it to be invalid. if ((int32_t) pName->n >= maxLen) { pName->n = -1; } else { strncpy(pField->name, pName->z, pName->n); pField->name[pName->n] = 0; } pField->type = pType->type; if(!isValidDataType(pField->type)){ pField->bytes = 0; } else { pField->bytes = pType->bytes; } } static int32_t tryParseNameTwoParts(SStrToken *type) { int32_t t = -1; char* str = strndup(type->z, type->n); if (str == NULL) { return t; } char* p = strtok(str, " "); if (p == NULL) { tfree(str); return t; } else { char* unsign = strtok(NULL, " "); if (unsign == NULL) { tfree(str); return t; } if (strncasecmp(unsign, "UNSIGNED", 8) == 0) { for(int32_t j = TSDB_DATA_TYPE_TINYINT; j <= TSDB_DATA_TYPE_BIGINT; ++j) { if (strcasecmp(p, tDataTypes[j].name) == 0) { t = j; break; } } tfree(str); if (t == -1) { return -1; } switch(t) { case TSDB_DATA_TYPE_TINYINT: return TSDB_DATA_TYPE_UTINYINT; case TSDB_DATA_TYPE_SMALLINT: return TSDB_DATA_TYPE_USMALLINT; case TSDB_DATA_TYPE_INT: return TSDB_DATA_TYPE_UINT; case TSDB_DATA_TYPE_BIGINT: return TSDB_DATA_TYPE_UBIGINT; default: return -1; } } else { tfree(str); return -1; } } } void tSetColumnType(TAOS_FIELD *pField, SStrToken *type) { // set the field type invalid pField->type = -1; pField->name[0] = 0; int32_t i = 0; while (i < tListLen(tDataTypes)) { if ((type->n == tDataTypes[i].nameLen) && (strncasecmp(type->z, tDataTypes[i].name, tDataTypes[i].nameLen) == 0)) { break; } i += 1; } // no qualified data type found, try unsigned data type if (i == tListLen(tDataTypes)) { i = tryParseNameTwoParts(type); if (i == -1) { return; } } pField->type = i; pField->bytes = tDataTypes[i].bytes; if (i == TSDB_DATA_TYPE_NCHAR) { /* * for nchar, the TOKENTYPE is the number of character, so the length is the * number of bytes in UCS-4 format, which is 4 times larger than the number of characters */ if (type->type == 0) { pField->bytes = 0; } else { int32_t bytes = -(int32_t)(type->type); if (bytes > (TSDB_MAX_NCHAR_LEN - VARSTR_HEADER_SIZE) / TSDB_NCHAR_SIZE) { // we have to postpone reporting the error because it cannot be done here // as pField->bytes is int16_t, use 'TSDB_MAX_NCHAR_LEN + 1' to avoid overflow bytes = TSDB_MAX_NCHAR_LEN + 1; } else { bytes = bytes * TSDB_NCHAR_SIZE + VARSTR_HEADER_SIZE; } pField->bytes = (int16_t)bytes; } } else if (i == TSDB_DATA_TYPE_BINARY) { /* for binary, the TOKENTYPE is the length of binary */ if (type->type == 0) { pField->bytes = 0; } else { int32_t bytes = -(int32_t)(type->type); if (bytes > TSDB_MAX_BINARY_LEN - VARSTR_HEADER_SIZE) { // refer comment for NCHAR above bytes = TSDB_MAX_BINARY_LEN + 1; } else { bytes += VARSTR_HEADER_SIZE; } pField->bytes = (int16_t)bytes; } } } /* * extract the select info out of sql string */ SSqlNode *tSetQuerySqlNode(SStrToken *pSelectToken, SArray *pSelNodeList, SRelationInfo *pFrom, tSqlExpr *pWhere, SArray *pGroupby, SArray *pSortOrder, SIntervalVal *pInterval, SSessionWindowVal *pSession, SStrToken *pSliding, SArray *pFill, SLimitVal *pLimit, SLimitVal *psLimit, tSqlExpr *pHaving) { assert(pSelNodeList != NULL); SSqlNode *pSqlNode = calloc(1, sizeof(SSqlNode)); // all later sql string are belonged to the stream sql pSqlNode->sqlstr = *pSelectToken; pSqlNode->sqlstr.n = (uint32_t)strlen(pSqlNode->sqlstr.z); pSqlNode->pSelNodeList = pSelNodeList; pSqlNode->from = pFrom; pSqlNode->pGroupby = pGroupby; pSqlNode->pSortOrder = pSortOrder; pSqlNode->pWhere = pWhere; pSqlNode->fillType = pFill; pSqlNode->pHaving = pHaving; if (pLimit != NULL) { pSqlNode->limit = *pLimit; } else { pSqlNode->limit.limit = -1; pSqlNode->limit.offset = 0; } if (psLimit != NULL) { pSqlNode->slimit = *psLimit; } else { pSqlNode->slimit.limit = -1; pSqlNode->slimit.offset = 0; } if (pInterval != NULL) { pSqlNode->interval = *pInterval; } else { TPARSER_SET_NONE_TOKEN(pSqlNode->interval.interval); TPARSER_SET_NONE_TOKEN(pSqlNode->interval.offset); } if (pSliding != NULL) { pSqlNode->sliding = *pSliding; } else { TPARSER_SET_NONE_TOKEN(pSqlNode->sliding); } if (pSession != NULL) { pSqlNode->sessionVal = *pSession; } else { TPARSER_SET_NONE_TOKEN(pSqlNode->sessionVal.gap); TPARSER_SET_NONE_TOKEN(pSqlNode->sessionVal.col); } return pSqlNode; } static void freeVariant(void *pItem) { tVariantListItem* p = (tVariantListItem*) pItem; tVariantDestroy(&p->pVar); } void freeCreateTableInfo(void* p) { SCreatedTableInfo* pInfo = (SCreatedTableInfo*) p; taosArrayDestroy(pInfo->pTagNames); taosArrayDestroyEx(pInfo->pTagVals, freeVariant); tfree(pInfo->fullname); tfree(pInfo->tagdata.data); } void destroySqlNode(SSqlNode *pSqlNode) { if (pSqlNode == NULL) { return; } tSqlExprListDestroy(pSqlNode->pSelNodeList); pSqlNode->pSelNodeList = NULL; tSqlExprDestroy(pSqlNode->pWhere); pSqlNode->pWhere = NULL; taosArrayDestroyEx(pSqlNode->pSortOrder, freeVariant); pSqlNode->pSortOrder = NULL; taosArrayDestroyEx(pSqlNode->pGroupby, freeVariant); pSqlNode->pGroupby = NULL; pSqlNode->from = destroyRelationInfo(pSqlNode->from); taosArrayDestroyEx(pSqlNode->fillType, freeVariant); pSqlNode->fillType = NULL; tSqlExprDestroy(pSqlNode->pHaving); free(pSqlNode); } void destroyAllSqlNode(SArray *pList) { if (pList == NULL) { return; } size_t size = taosArrayGetSize(pList); for(int32_t i = 0; i < size; ++i) { SSqlNode *pNode = taosArrayGetP(pList, i); destroySqlNode(pNode); } taosArrayDestroy(pList); } SCreateTableSql *tSetCreateTableInfo(SArray *pCols, SArray *pTags, SSqlNode *pSelect, int32_t type) { SCreateTableSql *pCreate = calloc(1, sizeof(SCreateTableSql)); switch (type) { case TSQL_CREATE_TABLE: { pCreate->colInfo.pColumns = pCols; assert(pTags == NULL); break; } case TSQL_CREATE_STABLE: { pCreate->colInfo.pColumns = pCols; pCreate->colInfo.pTagColumns = pTags; assert(pTags != NULL && pCols != NULL); break; } case TSQL_CREATE_STREAM: { pCreate->pSelect = pSelect; break; } case TSQL_CREATE_TABLE_FROM_STABLE: { assert(0); } default: assert(false); } pCreate->type = type; return pCreate; } SCreatedTableInfo createNewChildTableInfo(SStrToken *pTableName, SArray *pTagNames, SArray *pTagVals, SStrToken *pToken, SStrToken* igExists) { SCreatedTableInfo info; memset(&info, 0, sizeof(SCreatedTableInfo)); info.name = *pToken; info.pTagNames = pTagNames; info.pTagVals = pTagVals; info.stableName = *pTableName; info.igExist = (igExists->n > 0)? 1:0; return info; } SAlterTableInfo *tSetAlterTableInfo(SStrToken *pTableName, SArray *pCols, SArray *pVals, int32_t type, int16_t tableType) { SAlterTableInfo *pAlterTable = calloc(1, sizeof(SAlterTableInfo)); pAlterTable->name = *pTableName; pAlterTable->type = type; pAlterTable->tableType = tableType; if (type == TSDB_ALTER_TABLE_ADD_COLUMN || type == TSDB_ALTER_TABLE_ADD_TAG_COLUMN) { pAlterTable->pAddColumns = pCols; assert(pVals == NULL); } else { /* * ALTER_TABLE_TAGS_CHG, ALTER_TABLE_TAGS_SET, ALTER_TABLE_TAGS_DROP, * ALTER_TABLE_DROP_COLUMN */ pAlterTable->varList = pVals; assert(pCols == NULL); } return pAlterTable; } void* destroyCreateTableSql(SCreateTableSql* pCreate) { destroySqlNode(pCreate->pSelect); taosArrayDestroy(pCreate->colInfo.pColumns); taosArrayDestroy(pCreate->colInfo.pTagColumns); taosArrayDestroyEx(pCreate->childTableInfo, freeCreateTableInfo); tfree(pCreate); return NULL; } void SqlInfoDestroy(SSqlInfo *pInfo) { if (pInfo == NULL) return; if (pInfo->type == TSDB_SQL_SELECT) { destroyAllSqlNode(pInfo->list); } else if (pInfo->type == TSDB_SQL_CREATE_TABLE) { pInfo->pCreateTableInfo = destroyCreateTableSql(pInfo->pCreateTableInfo); } else if (pInfo->type == TSDB_SQL_ALTER_TABLE) { taosArrayDestroyEx(pInfo->pAlterInfo->varList, freeVariant); taosArrayDestroy(pInfo->pAlterInfo->pAddColumns); tfree(pInfo->pAlterInfo->tagData.data); tfree(pInfo->pAlterInfo); } else { if (pInfo->pMiscInfo != NULL) { taosArrayDestroy(pInfo->pMiscInfo->a); } if (pInfo->pMiscInfo != NULL && pInfo->type == TSDB_SQL_CREATE_DB) { taosArrayDestroyEx(pInfo->pMiscInfo->dbOpt.keep, freeVariant); } tfree(pInfo->pMiscInfo); } } SArray* setSubclause(SArray* pList, void *pSqlNode) { if (pList == NULL) { pList = taosArrayInit(1, POINTER_BYTES); } taosArrayPush(pList, &pSqlNode); return pList; } SSqlInfo* setSqlInfo(SSqlInfo *pInfo, void *pSqlExprInfo, SStrToken *pTableName, int32_t type) { pInfo->type = type; if (type == TSDB_SQL_SELECT) { pInfo->list = (SArray*) pSqlExprInfo; } else { pInfo->pCreateTableInfo = pSqlExprInfo; } if (pTableName != NULL) { pInfo->pCreateTableInfo->name = *pTableName; } return pInfo; } SArray* appendSelectClause(SArray *pList, void *pSubclause) { taosArrayPush(pList, &pSubclause); return pList; } void setCreatedTableName(SSqlInfo *pInfo, SStrToken *pTableNameToken, SStrToken *pIfNotExists) { pInfo->pCreateTableInfo->name = *pTableNameToken; pInfo->pCreateTableInfo->existCheck = (pIfNotExists->n != 0); } void setDCLSqlElems(SSqlInfo *pInfo, int32_t type, int32_t nParam, ...) { pInfo->type = type; if (nParam == 0) { return; } if (pInfo->pMiscInfo == NULL) { pInfo->pMiscInfo = (SMiscInfo *)calloc(1, sizeof(SMiscInfo)); pInfo->pMiscInfo->a = taosArrayInit(4, sizeof(SStrToken)); } va_list va; va_start(va, nParam); while ((nParam--) > 0) { SStrToken *pToken = va_arg(va, SStrToken *); taosArrayPush(pInfo->pMiscInfo->a, pToken); } va_end(va); } void setDropDbTableInfo(SSqlInfo *pInfo, int32_t type, SStrToken* pToken, SStrToken* existsCheck, int16_t dbType, int16_t tableType) { pInfo->type = type; if (pInfo->pMiscInfo == NULL) { pInfo->pMiscInfo = (SMiscInfo *)calloc(1, sizeof(SMiscInfo)); pInfo->pMiscInfo->a = taosArrayInit(4, sizeof(SStrToken)); } taosArrayPush(pInfo->pMiscInfo->a, pToken); pInfo->pMiscInfo->existsCheck = (existsCheck->n == 1); pInfo->pMiscInfo->dbType = dbType; pInfo->pMiscInfo->tableType = tableType; } void setShowOptions(SSqlInfo *pInfo, int32_t type, SStrToken* prefix, SStrToken* pPatterns) { if (pInfo->pMiscInfo == NULL) { pInfo->pMiscInfo = calloc(1, sizeof(SMiscInfo)); } pInfo->type = TSDB_SQL_SHOW; SShowInfo* pShowInfo = &pInfo->pMiscInfo->showOpt; pShowInfo->showType = type; if (prefix != NULL && prefix->type != 0) { pShowInfo->prefix = *prefix; } else { pShowInfo->prefix.type = 0; } if (pPatterns != NULL && pPatterns->type != 0) { pShowInfo->pattern = *pPatterns; } else { pShowInfo->pattern.type = 0; } } void setCreateDbInfo(SSqlInfo *pInfo, int32_t type, SStrToken *pToken, SCreateDbInfo *pDB, SStrToken *pIgExists) { pInfo->type = type; if (pInfo->pMiscInfo == NULL) { pInfo->pMiscInfo = calloc(1, sizeof(SMiscInfo)); } pInfo->pMiscInfo->dbOpt = *pDB; pInfo->pMiscInfo->dbOpt.dbname = *pToken; pInfo->pMiscInfo->dbOpt.ignoreExists = pIgExists->n; // sql.y has: ifnotexists(X) ::= IF NOT EXISTS. {X.n = 1;} } void setCreateAcctSql(SSqlInfo *pInfo, int32_t type, SStrToken *pName, SStrToken *pPwd, SCreateAcctInfo *pAcctInfo) { pInfo->type = type; if (pInfo->pMiscInfo == NULL) { pInfo->pMiscInfo = calloc(1, sizeof(SMiscInfo)); } pInfo->pMiscInfo->acctOpt = *pAcctInfo; assert(pName != NULL); pInfo->pMiscInfo->user.user = *pName; if (pPwd != NULL) { pInfo->pMiscInfo->user.passwd = *pPwd; } } void setCreateUserSql(SSqlInfo *pInfo, SStrToken *pName, SStrToken *pPasswd) { pInfo->type = TSDB_SQL_CREATE_USER; if (pInfo->pMiscInfo == NULL) { pInfo->pMiscInfo = calloc(1, sizeof(SMiscInfo)); } assert(pName != NULL && pPasswd != NULL); pInfo->pMiscInfo->user.user = *pName; pInfo->pMiscInfo->user.passwd = *pPasswd; } void setAlterUserSql(SSqlInfo *pInfo, int16_t type, SStrToken *pName, SStrToken* pPwd, SStrToken *pPrivilege) { pInfo->type = TSDB_SQL_ALTER_USER; if (pInfo->pMiscInfo == NULL) { pInfo->pMiscInfo = calloc(1, sizeof(SMiscInfo)); } assert(pName != NULL); SUserInfo* pUser = &pInfo->pMiscInfo->user; pUser->type = type; pUser->user = *pName; if (pPwd != NULL) { pUser->passwd = *pPwd; } else { pUser->passwd.type = TSDB_DATA_TYPE_NULL; } if (pPrivilege != NULL) { pUser->privilege = *pPrivilege; } else { pUser->privilege.type = TSDB_DATA_TYPE_NULL; } } void setKillSql(SSqlInfo *pInfo, int32_t type, SStrToken *id) { pInfo->type = type; if (pInfo->pMiscInfo == NULL) { pInfo->pMiscInfo = calloc(1, sizeof(SMiscInfo)); } assert(id != NULL); pInfo->pMiscInfo->id = *id; } void setDefaultCreateDbOption(SCreateDbInfo *pDBInfo) { pDBInfo->compressionLevel = -1; pDBInfo->walLevel = -1; pDBInfo->fsyncPeriod = -1; pDBInfo->commitTime = -1; pDBInfo->maxTablesPerVnode = -1; pDBInfo->cacheBlockSize = -1; pDBInfo->numOfBlocks = -1; pDBInfo->maxRowsPerBlock = -1; pDBInfo->minRowsPerBlock = -1; pDBInfo->daysPerFile = -1; pDBInfo->replica = -1; pDBInfo->quorum = -1; pDBInfo->keep = NULL; pDBInfo->update = -1; pDBInfo->cachelast = -1; pDBInfo->dbType = -1; pDBInfo->partitions = -1; memset(&pDBInfo->precision, 0, sizeof(SStrToken)); } void setDefaultCreateTopicOption(SCreateDbInfo *pDBInfo) { setDefaultCreateDbOption(pDBInfo); pDBInfo->dbType = TSDB_DB_TYPE_TOPIC; pDBInfo->partitions = TSDB_DEFAULT_DB_PARTITON_OPTION; }