homework-jianmu/source/libs/parser/src/astGenerator.c

1159 lines
30 KiB
C

/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "os.h"
#include "taos.h"
#include "tmsg.h"
#include "parserInt.h"
#include "tmsgtype.h"
#include "astGenerator.h"
SArray *tListItemAppend(SArray *pList, SVariant *pVar, uint8_t sortOrder) {
if (pList == NULL) {
pList = taosArrayInit(4, sizeof(SListItem));
}
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.
* Otherwise, the original pointer may be lost, which causes memory leak.
*/
SListItem item;
item.pVar = *pVar;
item.sortOrder = sortOrder;
taosArrayPush(pList, &item);
return pList;
}
SArray *tListItemInsert(SArray *pList, SVariant *pVar, uint8_t sortOrder, int32_t index) {
if (pList == NULL || pVar == NULL || index >= taosArrayGetSize(pList)) {
return tListItemAppend(pList, pVar, sortOrder);
}
SListItem item;
item.pVar = *pVar;
item.sortOrder = sortOrder;
taosArrayInsert(pList, index, &item);
return pList;
}
SArray *tListItemAppendToken(SArray *pList, SToken *pAliasToken, uint8_t sortOrder) {
if (pList == NULL) {
pList = taosArrayInit(4, sizeof(SListItem));
}
if (pAliasToken) {
SListItem item;
taosVariantCreate(&item.pVar, pAliasToken->z, pAliasToken->n, pAliasToken->type);
item.sortOrder = sortOrder;
taosArrayPush(pList, &item);
}
return pList;
}
SRelationInfo *setTableNameList(SRelationInfo *pRelationInfo, SToken *pName, SToken *pAlias) {
if (pRelationInfo == NULL) {
pRelationInfo = calloc(1, sizeof(SRelationInfo));
pRelationInfo->list = taosArrayInit(4, sizeof(SRelElement));
}
pRelationInfo->type = SQL_FROM_NODE_TABLES;
SRelElement p = {.tableName = *pName};
if (pAlias != NULL) {
p.aliasName = *pAlias;
} else {
TPARSER_SET_NONE_TOKEN(p.aliasName);
}
taosArrayPush(pRelationInfo->list, &p);
return pRelationInfo;
}
void *destroyRelationInfo(SRelationInfo *pRelationInfo) {
if (pRelationInfo == NULL) {
return NULL;
}
if (pRelationInfo->type == SQL_FROM_NODE_TABLES) {
taosArrayDestroy(pRelationInfo->list);
} else {
size_t size = taosArrayGetSize(pRelationInfo->list);
for(int32_t i = 0; i < size; ++i) {
SSubclause* pa = taosArrayGetP(pRelationInfo->list, i);
destroyAllSqlNode(pa);
}
taosArrayDestroy(pRelationInfo->list);
}
tfree(pRelationInfo);
return NULL;
}
SRelationInfo *addSubquery(SRelationInfo *pRelationInfo, SSubclause *pSub, SToken *pAlias) {
if (pRelationInfo == NULL) {
pRelationInfo = calloc(1, sizeof(SRelationInfo));
pRelationInfo->list = taosArrayInit(4, sizeof(SRelElement));
}
pRelationInfo->type = SQL_FROM_NODE_SUBQUERY;
SRelElement p = {.pSubquery = pSub};
if (pAlias != NULL) {
p.aliasName = *pAlias;
} else {
TPARSER_SET_NONE_TOKEN(p.aliasName);
}
taosArrayPush(pRelationInfo->list, &p);
return pRelationInfo;
}
// sql expr leaf node
tSqlExpr *tSqlExprCreateIdValue(SToken *pToken, int32_t optrType) {
tSqlExpr *pSqlExpr = calloc(1, sizeof(tSqlExpr));
if (pToken != NULL) {
pSqlExpr->exprToken = *pToken;
}
if (optrType == TK_NULL) {
// if (pToken) {
// 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) {
pSqlExpr->tokenId = optrType;
pSqlExpr->type = SQL_NODE_VALUE;
} 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.
assert(optrType == TK_ID || optrType == TK_ALL);
if (pToken != NULL) {
pSqlExpr->columnName = *pToken;
}
pSqlExpr->tokenId = optrType;
pSqlExpr->type = SQL_NODE_TABLE_COLUMN;
}
return pSqlExpr;
}
tSqlExpr *tSqlExprCreateFunction(SArray *pParam, SToken *pFuncToken, SToken *endToken, int32_t optType) {
if (pFuncToken == NULL) {
return NULL;
}
tSqlExpr *pExpr = calloc(1, sizeof(tSqlExpr));
pExpr->tokenId = optType;
pExpr->type = SQL_NODE_SQLFUNCTION;
pExpr->Expr.paramList = pParam;
int32_t len = (int32_t)((endToken->z + endToken->n) - pFuncToken->z);
pExpr->Expr.operand = (*pFuncToken);
pExpr->exprToken.n = len;
pExpr->exprToken.z = pFuncToken->z;
pExpr->exprToken.type = pFuncToken->type;
return pExpr;
}
SArray *tRecordFuncName(SArray *pList, SToken *pToken) {
assert(pList != NULL && pToken != NULL);
taosArrayPush(pList, pToken);
return pList;
}
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)) {
const char* endPos = pRight->exprToken.z + pRight->exprToken.n;
pExpr->exprToken.z = pLeft->exprToken.z;
pExpr->exprToken.n = (uint32_t)(endPos - pExpr->exprToken.z);
pExpr->exprToken.type = pLeft->exprToken.type;
}
if (optrType == TK_IN) {
pExpr->tokenId = optrType;
pExpr->pLeft = pLeft;
tSqlExpr *pRSub = calloc(1, sizeof(tSqlExpr));
pRSub->tokenId = TK_SET; // TODO refactor .....
pRSub->Expr.paramList = (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;
}
tSqlExpr *tSqlExprClone(tSqlExpr *pSrc) {
tSqlExpr *pExpr = malloc(sizeof(tSqlExpr));
memcpy(pExpr, pSrc, sizeof(*pSrc));
if (pSrc->pLeft) {
pExpr->pLeft = tSqlExprClone(pSrc->pLeft);
}
if (pSrc->pRight) {
pExpr->pRight = tSqlExprClone(pSrc->pRight);
}
memset(&pExpr->value, 0, sizeof(pExpr->value));
taosVariantAssign(&pExpr->value, &pSrc->value);
//we don't clone paramList now because clone is only used for between/and
assert(pSrc->Expr.paramList == 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_STRING || pExpr->tokenId == TK_FLOAT) ||
(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;
}
taosVariantDestroy(&pExpr->value);
tSqlExprListDestroy(pExpr->Expr.paramList);
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 * tSqlExprListAppend(SArray *pList, tSqlExpr *pNode, SToken *pDistinct, SToken *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);
}
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.i = pLeft->value.i + pRight->value.i;
break;
}
case TK_MINUS: {
pExpr->value.i = pLeft->value.i - pRight->value.i;
break;
}
case TK_STAR: {
pExpr->value.i = pLeft->value.i * pRight->value.i;
break;
}
case TK_DIVIDE: {
pExpr->tokenId = TK_FLOAT;
pExpr->value.nType = TSDB_DATA_TYPE_DOUBLE;
pExpr->value.d = (double)pLeft->value.i / pRight->value.i;
break;
}
case TK_REM: {
pExpr->value.i = pLeft->value.i % pRight->value.i;
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.i;
double right = (pRight->value.nType == TSDB_DATA_TYPE_DOUBLE) ? pRight->value.d : pRight->value.i;
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,
SLimit *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);
}
if (pWindowStateVal != NULL) {
pSqlNode->windowstateVal = *pWindowStateVal;
} else {
TPARSER_SET_NONE_TOKEN(pSqlNode->windowstateVal.col);
}
return pSqlNode;
}
static FORCE_INLINE int32_t tStrTokenCompare(SToken* left, SToken* 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) || (left == NULL && right == NULL)) {
return 1;
}
if (left->type != right->type) {
return 1;
}
if (left->tokenId != right->tokenId) {
return 1;
}
if ((left->pLeft && right->pLeft == NULL)
|| (left->pLeft == NULL && right->pLeft)
|| (left->pRight && right->pRight == NULL)
|| (left->pRight == NULL && right->pRight)
|| (left->Expr.paramList && right->Expr.paramList == NULL)
|| (left->Expr.paramList == NULL && right->Expr.paramList)) {
return 1;
}
if (taosVariantCompare(&left->value, &right->value)) {
return 1;
}
if (tStrTokenCompare(&left->columnName, &right->columnName)) {
return 1;
}
if (right->Expr.paramList && left->Expr.paramList) {
size_t size = taosArrayGetSize(right->Expr.paramList);
if (left->Expr.paramList && taosArrayGetSize(left->Expr.paramList) != size) {
return 1;
}
for (int32_t i = 0; i < size; i++) {
tSqlExprItem* pLeftElem = taosArrayGet(left->Expr.paramList, i);
tSqlExpr* pSubLeft = pLeftElem->pNode;
tSqlExprItem* pRightElem = taosArrayGet(right->Expr.paramList, 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;
}
SCreateTableSql *tSetCreateTableInfo(SArray *pCols, SArray *pTags, SSqlNode *pSelect, int32_t type) {
SCreateTableSql *pCreate = calloc(1, sizeof(SCreateTableSql));
switch (type) {
case TSDB_SQL_CREATE_TABLE: {
pCreate->colInfo.pColumns = pCols;
assert(pTags == NULL);
break;
}
case TSDB_SQL_CREATE_STABLE: {
pCreate->colInfo.pColumns = pCols;
pCreate->colInfo.pTagColumns = pTags;
assert(pTags != NULL && pCols != NULL);
break;
}
// case TSQL_CREATE_STREAM: {
// pCreate->pSelect = pSelect;
// break;
// }
default:
assert(false);
}
pCreate->type = type;
return pCreate;
}
SAlterTableInfo *tSetAlterTableInfo(SToken *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 || type == TSDB_ALTER_TABLE_CHANGE_COLUMN || type == TSDB_ALTER_TABLE_MODIFY_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;
}
SCreatedTableInfo createNewChildTableInfo(SToken *pTableName, SArray *pTagNames, SArray *pTagVals, SToken *pToken, SToken* igExists) {
SCreatedTableInfo info;
memset(&info, 0, sizeof(SCreatedTableInfo));
info.name = *pToken;
info.pTagNames = pTagNames;
info.pTagVals = pTagVals;
info.stbName = *pTableName;
info.igExist = (igExists->n > 0)? 1:0;
return info;
}
void destroyAllSqlNode(struct SSubclause *pSub) {
if (pSub->node == NULL) {
return;
}
size_t size = taosArrayGetSize(pSub->node);
for(int32_t i = 0; i < size; ++i) {
SSqlNode *pNode = taosArrayGetP(pSub->node, i);
destroySqlNode(pNode);
}
taosArrayDestroy(pSub->node);
}
static void freeItem(void *pItem) {
SListItem* p = (SListItem*) pItem;
taosVariantDestroy(&p->pVar);
}
void destroySqlNode(SSqlNode *pSqlNode) {
if (pSqlNode == NULL) {
return;
}
tSqlExprListDestroy(pSqlNode->pSelNodeList);
pSqlNode->pSelNodeList = NULL;
tSqlExprDestroy(pSqlNode->pWhere);
pSqlNode->pWhere = NULL;
taosArrayDestroyEx(pSqlNode->pSortOrder, freeItem);
pSqlNode->pSortOrder = NULL;
taosArrayDestroyEx(pSqlNode->pGroupby, freeItem);
pSqlNode->pGroupby = NULL;
pSqlNode->from = destroyRelationInfo(pSqlNode->from);
taosArrayDestroyEx(pSqlNode->fillType, freeItem);
pSqlNode->fillType = NULL;
tSqlExprDestroy(pSqlNode->pHaving);
free(pSqlNode);
}
void freeCreateTableInfo(void* p) {
SCreatedTableInfo* pInfo = (SCreatedTableInfo*) p;
taosArrayDestroy(pInfo->pTagNames);
taosArrayDestroy(pInfo->pTagVals);
tfree(pInfo->fullname);
}
SSqlInfo* setSqlInfo(SSqlInfo *pInfo, void *pSqlExprInfo, SToken *pTableName, int32_t type) {
pInfo->type = type;
if (type == TSDB_SQL_SELECT) {
pInfo->sub = *(SSubclause*) pSqlExprInfo;
tfree(pSqlExprInfo);
} else {
pInfo->pCreateTableInfo = pSqlExprInfo;
}
if (pTableName != NULL) {
pInfo->pCreateTableInfo->name = *pTableName;
}
return pInfo;
}
SSubclause* setSubclause(SSubclause* pSub, void *pSqlNode) {
if (pSub == NULL) {
pSub = malloc(sizeof(SSubclause));
pSub->unionType = SQL_TYPE_UNIONALL;
pSub->node = taosArrayInit(1, POINTER_BYTES);
}
taosArrayPush(pSub->node, &pSqlNode);
return pSub;
}
SSubclause* appendSelectClause(SSubclause *pSub, int32_t type, void *pSubclause) {
taosArrayPush(pSub->node, &pSubclause);
if (type == SQL_TYPE_UNION) {
pSub->unionType = type;
}
return pSub;
}
void setCreatedTableName(SSqlInfo *pInfo, SToken *pTableNameToken, SToken *pIfNotExists) {
pInfo->pCreateTableInfo->name = *pTableNameToken;
pInfo->pCreateTableInfo->existCheck = (pIfNotExists->n != 0);
}
void* destroyCreateTableSql(SCreateTableSql* pCreate) {
destroySqlNode(pCreate->pSelect);
taosArrayDestroy(pCreate->colInfo.pColumns);
taosArrayDestroy(pCreate->colInfo.pTagColumns);
taosArrayDestroyEx(pCreate->childTableInfo, freeCreateTableInfo);
tfree(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 destroySqlInfo(SSqlInfo *pInfo) {
if (pInfo == NULL) {
return;
}
taosArrayDestroy(pInfo->funcs);
if (pInfo->type == TSDB_SQL_SELECT) {
destroyAllSqlNode(&pInfo->sub);
} else if (pInfo->type == TSDB_SQL_CREATE_STABLE || pInfo->type == TSDB_SQL_CREATE_TABLE) {
pInfo->pCreateTableInfo = destroyCreateTableSql(pInfo->pCreateTableInfo);
} else if (pInfo->type == TSDB_SQL_ALTER_TABLE) {
taosArrayDestroyEx(pInfo->pAlterInfo->varList, freeItem);
taosArrayDestroy(pInfo->pAlterInfo->pAddColumns);
tfree(pInfo->pAlterInfo->tagData.data);
tfree(pInfo->pAlterInfo);
} else if (pInfo->type == TSDB_SQL_COMPACT_VNODE) {
tSqlExprListDestroy(pInfo->sub.node);
} else {
if (pInfo->pMiscInfo != NULL) {
taosArrayDestroy(pInfo->pMiscInfo->a);
}
if (pInfo->pMiscInfo != NULL && (pInfo->type == TSDB_SQL_CREATE_DB || pInfo->type == TSDB_SQL_ALTER_DB)) {
taosArrayDestroyEx(pInfo->pMiscInfo->dbOpt.keep, freeItem);
}
tfree(pInfo->pMiscInfo);
}
}
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(SToken));
}
va_list va;
va_start(va, nParam);
while ((nParam--) > 0) {
SToken *pToken = va_arg(va, SToken *);
taosArrayPush(pInfo->pMiscInfo->a, pToken);
}
va_end(va);
}
void setDropDbTableInfo(SSqlInfo *pInfo, int32_t type, SToken* pToken, SToken* 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(SToken));
}
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, SToken* prefix, SToken* 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, SToken *pToken, SCreateDbInfo *pDB, SToken *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, SToken *pName, SToken *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, SToken *pName, SToken *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 setKillSql(SSqlInfo *pInfo, int32_t type, SToken *id) {
pInfo->type = type;
if (pInfo->pMiscInfo == NULL) {
pInfo->pMiscInfo = calloc(1, sizeof(SMiscInfo));
}
assert(id != NULL);
pInfo->pMiscInfo->id = *id;
}
void setAlterUserSql(SSqlInfo *pInfo, int16_t type, SToken *pName, SToken* pPwd, SToken *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 setCompactVnodeSql(SSqlInfo *pInfo, int32_t type, SArray *pParam) {
pInfo->type = type;
pInfo->sub.node = pParam;
}
void setDefaultCreateDbOption(SCreateDbInfo *pDBInfo) {
pDBInfo->compressionLevel= -1;
pDBInfo->walLevel = -1;
pDBInfo->fsyncPeriod = -1;
pDBInfo->commitTime = -1;
pDBInfo->numOfVgroups = 2;
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;
memset(&pDBInfo->precision, 0, sizeof(SToken));
}
// prefix show db.tables;
void tSetDbName(SToken *pCpxName, SToken *pDb) {
pCpxName->type = pDb->type;
pCpxName->z = pDb->z;
pCpxName->n = pDb->n;
}
void tSetColumnInfo(SField *pField, SToken *pName, SField *pType) {
int32_t maxLen = sizeof(pField->name) / sizeof(pField->name[0]);
// The column name is too long, set it to be invalid.
if ((int32_t) pName->n >= maxLen) {
pField->name[0] = 0;
} else {
strncpy(pField->name, pName->z, pName->n);
pField->name[pName->n] = 0;
}
// denote an invalid data type in the column definition.
pField->type = pType->type;
if(!isValidDataType(pField->type)){
pField->bytes = 0;
} else {
pField->bytes = pType->bytes;
}
}
static int32_t tryParseNameTwoParts(SToken *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(SField *pField, SToken *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) {
// overflowed. set bytes to -1 so that error can be reported
bytes = -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) {
// overflowed. set bytes to -1 so that error can be reported
bytes = -1;
} else {
bytes += VARSTR_HEADER_SIZE;
}
pField->bytes = (int16_t)bytes;
}
}
}
SSqlInfo doGenerateAST(const char *pStr) {
void *pParser = ParseAlloc(malloc);
SSqlInfo sqlInfo = {0};
sqlInfo.valid = true;
sqlInfo.funcs = taosArrayInit(4, sizeof(SToken));
int32_t i = 0;
while (1) {
SToken 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;
}