Merge pull request #12030 from taosdata/feature/3.0_wxy
enh: refactor unit test of parser and planner
This commit is contained in:
commit
08504bd9df
|
@ -22,19 +22,20 @@ extern "C" {
|
|||
|
||||
#include "tdef.h"
|
||||
|
||||
#define nodeType(nodeptr) (((const SNode*)(nodeptr))->type)
|
||||
#define nodeType(nodeptr) (((const SNode*)(nodeptr))->type)
|
||||
#define setNodeType(nodeptr, type) (((SNode*)(nodeptr))->type = (type))
|
||||
|
||||
#define LIST_LENGTH(l) (NULL != (l) ? (l)->length : 0)
|
||||
|
||||
#define FOREACH(node, list) \
|
||||
for (SListCell* cell = (NULL != (list) ? (list)->pHead : NULL); (NULL != cell ? (node = cell->pNode, true) : (node = NULL, false)); cell = cell->pNext)
|
||||
#define FOREACH(node, list) \
|
||||
for (SListCell* cell = (NULL != (list) ? (list)->pHead : NULL); \
|
||||
(NULL != cell ? (node = cell->pNode, true) : (node = NULL, false)); cell = cell->pNext)
|
||||
|
||||
#define REPLACE_NODE(newNode) cell->pNode = (SNode*)(newNode)
|
||||
|
||||
#define INSERT_LIST(target, src) nodesListInsertList((target), cell, src)
|
||||
|
||||
#define WHERE_EACH(node, list) \
|
||||
#define WHERE_EACH(node, list) \
|
||||
SListCell* cell = (NULL != (list) ? (list)->pHead : NULL); \
|
||||
while (NULL != cell ? (node = cell->pNode, true) : (node = NULL, false))
|
||||
|
||||
|
@ -43,16 +44,26 @@ extern "C" {
|
|||
// only be use in WHERE_EACH
|
||||
#define ERASE_NODE(list) cell = nodesListErase((list), cell)
|
||||
|
||||
#define FORBOTH(node1, list1, node2, list2) \
|
||||
for (SListCell* cell1 = (NULL != (list1) ? (list1)->pHead : NULL), *cell2 = (NULL != (list2) ? (list2)->pHead : NULL); \
|
||||
(NULL == cell1 ? (node1 = NULL, false) : (node1 = cell1->pNode, true)), (NULL == cell2 ? (node2 = NULL, false) : (node2 = cell2->pNode, true)), (node1 != NULL && node2 != NULL); \
|
||||
cell1 = cell1->pNext, cell2 = cell2->pNext)
|
||||
#define FORBOTH(node1, list1, node2, list2) \
|
||||
for (SListCell* cell1 = (NULL != (list1) ? (list1)->pHead : NULL), \
|
||||
*cell2 = (NULL != (list2) ? (list2)->pHead : NULL); \
|
||||
(NULL == cell1 ? (node1 = NULL, false) : (node1 = cell1->pNode, true)), \
|
||||
(NULL == cell2 ? (node2 = NULL, false) : (node2 = cell2->pNode, true)), \
|
||||
(node1 != NULL && node2 != NULL); \
|
||||
cell1 = cell1->pNext, cell2 = cell2->pNext)
|
||||
|
||||
#define REPLACE_LIST1_NODE(newNode) cell1->pNode = (SNode*)(newNode)
|
||||
#define REPLACE_LIST2_NODE(newNode) cell2->pNode = (SNode*)(newNode)
|
||||
|
||||
#define FOREACH_FOR_REWRITE(node, list) \
|
||||
for (SListCell* cell = (NULL != (list) ? (list)->pHead : NULL); (NULL != cell ? (node = &(cell->pNode), true) : (node = NULL, false)); cell = cell->pNext)
|
||||
#define FOREACH_FOR_REWRITE(node, list) \
|
||||
for (SListCell* cell = (NULL != (list) ? (list)->pHead : NULL); \
|
||||
(NULL != cell ? (node = &(cell->pNode), true) : (node = NULL, false)); cell = cell->pNext)
|
||||
|
||||
#define DESTORY_LIST(list) \
|
||||
do { \
|
||||
nodesDestroyList(list); \
|
||||
list = NULL; \
|
||||
} while (0)
|
||||
|
||||
typedef enum ENodeType {
|
||||
// Syntax nodes are used in parser and planner module, and some are also used in executor module, such as COLUMN,
|
||||
|
@ -211,11 +222,11 @@ typedef struct SNode {
|
|||
typedef struct SListCell {
|
||||
struct SListCell* pPrev;
|
||||
struct SListCell* pNext;
|
||||
SNode* pNode;
|
||||
SNode* pNode;
|
||||
} SListCell;
|
||||
|
||||
typedef struct SNodeList {
|
||||
int32_t length;
|
||||
int32_t length;
|
||||
SListCell* pHead;
|
||||
SListCell* pTail;
|
||||
} SNodeList;
|
||||
|
@ -223,29 +234,24 @@ typedef struct SNodeList {
|
|||
#define SNodeptr void*
|
||||
|
||||
SNodeptr nodesMakeNode(ENodeType type);
|
||||
void nodesDestroyNode(SNodeptr pNode);
|
||||
void nodesDestroyNode(SNodeptr pNode);
|
||||
|
||||
SNodeList* nodesMakeList();
|
||||
int32_t nodesListAppend(SNodeList* pList, SNodeptr pNode);
|
||||
int32_t nodesListStrictAppend(SNodeList* pList, SNodeptr pNode);
|
||||
int32_t nodesListMakeAppend(SNodeList** pList, SNodeptr pNode);
|
||||
int32_t nodesListMakeStrictAppend(SNodeList** pList, SNodeptr pNode);
|
||||
int32_t nodesListAppendList(SNodeList* pTarget, SNodeList* pSrc);
|
||||
int32_t nodesListStrictAppendList(SNodeList* pTarget, SNodeList* pSrc);
|
||||
int32_t nodesListPushFront(SNodeList* pList, SNodeptr pNode);
|
||||
int32_t nodesListAppend(SNodeList* pList, SNodeptr pNode);
|
||||
int32_t nodesListStrictAppend(SNodeList* pList, SNodeptr pNode);
|
||||
int32_t nodesListMakeAppend(SNodeList** pList, SNodeptr pNode);
|
||||
int32_t nodesListMakeStrictAppend(SNodeList** pList, SNodeptr pNode);
|
||||
int32_t nodesListAppendList(SNodeList* pTarget, SNodeList* pSrc);
|
||||
int32_t nodesListStrictAppendList(SNodeList* pTarget, SNodeList* pSrc);
|
||||
int32_t nodesListPushFront(SNodeList* pList, SNodeptr pNode);
|
||||
SListCell* nodesListErase(SNodeList* pList, SListCell* pCell);
|
||||
void nodesListInsertList(SNodeList* pTarget, SListCell* pPos, SNodeList* pSrc);
|
||||
SNodeptr nodesListGetNode(SNodeList* pList, int32_t index);
|
||||
void nodesDestroyList(SNodeList* pList);
|
||||
void nodesListInsertList(SNodeList* pTarget, SListCell* pPos, SNodeList* pSrc);
|
||||
SNodeptr nodesListGetNode(SNodeList* pList, int32_t index);
|
||||
void nodesDestroyList(SNodeList* pList);
|
||||
// Only clear the linked list structure, without releasing the elements inside
|
||||
void nodesClearList(SNodeList* pList);
|
||||
|
||||
typedef enum EDealRes {
|
||||
DEAL_RES_CONTINUE = 1,
|
||||
DEAL_RES_IGNORE_CHILD,
|
||||
DEAL_RES_ERROR,
|
||||
DEAL_RES_END
|
||||
} EDealRes;
|
||||
typedef enum EDealRes { DEAL_RES_CONTINUE = 1, DEAL_RES_IGNORE_CHILD, DEAL_RES_ERROR, DEAL_RES_END } EDealRes;
|
||||
|
||||
typedef EDealRes (*FNodeWalker)(SNode* pNode, void* pContext);
|
||||
void nodesWalkExpr(SNodeptr pNode, FNodeWalker walker, void* pContext);
|
||||
|
@ -261,18 +267,18 @@ void nodesRewriteExprsPostOrder(SNodeList* pList, FNodeRewriter rewriter, void*
|
|||
|
||||
bool nodesEqualNode(const SNodeptr a, const SNodeptr b);
|
||||
|
||||
SNodeptr nodesCloneNode(const SNodeptr pNode);
|
||||
SNodeptr nodesCloneNode(const SNodeptr pNode);
|
||||
SNodeList* nodesCloneList(const SNodeList* pList);
|
||||
|
||||
const char* nodesNodeName(ENodeType type);
|
||||
int32_t nodesNodeToString(const SNodeptr pNode, bool format, char** pStr, int32_t* pLen);
|
||||
int32_t nodesStringToNode(const char* pStr, SNode** pNode);
|
||||
int32_t nodesNodeToString(const SNodeptr pNode, bool format, char** pStr, int32_t* pLen);
|
||||
int32_t nodesStringToNode(const char* pStr, SNode** pNode);
|
||||
|
||||
int32_t nodesListToString(const SNodeList* pList, bool format, char** pStr, int32_t* pLen);
|
||||
int32_t nodesStringToList(const char* pStr, SNodeList** pList);
|
||||
|
||||
int32_t nodesNodeToSQL(SNode *pNode, char *buf, int32_t bufSize, int32_t *len);
|
||||
char *nodesGetNameFromColumnNode(SNode *pNode);
|
||||
int32_t nodesNodeToSQL(SNode* pNode, char* buf, int32_t bufSize, int32_t* len);
|
||||
char* nodesGetNameFromColumnNode(SNode* pNode);
|
||||
int32_t nodesGetOutputNumFromSlotList(SNodeList* pSlots);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -294,13 +294,14 @@ void nodesWalkSelectStmt(SSelectStmt* pSelect, ESqlClause clause, FNodeWalker wa
|
|||
void nodesRewriteSelectStmt(SSelectStmt* pSelect, ESqlClause clause, FNodeRewriter rewriter, void* pContext);
|
||||
|
||||
typedef enum ECollectColType { COLLECT_COL_TYPE_COL = 1, COLLECT_COL_TYPE_TAG, COLLECT_COL_TYPE_ALL } ECollectColType;
|
||||
|
||||
int32_t nodesCollectColumns(SSelectStmt* pSelect, ESqlClause clause, const char* pTableAlias, ECollectColType type,
|
||||
SNodeList** pCols);
|
||||
|
||||
typedef bool (*FFuncClassifier)(int32_t funcId);
|
||||
int32_t nodesCollectFuncs(SSelectStmt* pSelect, FFuncClassifier classifier, SNodeList** pFuncs);
|
||||
|
||||
int32_t nodesCollectSpecialNodes(SSelectStmt* pSelect, ESqlClause clause, ENodeType type, SNodeList** pNodes);
|
||||
|
||||
bool nodesIsExprNode(const SNode* pNode);
|
||||
|
||||
bool nodesIsUnaryOp(const SOperatorNode* pOp);
|
||||
|
|
|
@ -588,6 +588,259 @@ static int32_t jsonToLogicSortNode(const SJson* pJson, void* pObj) {
|
|||
return code;
|
||||
}
|
||||
|
||||
static const char* jkPartitionLogicPlanPartitionKeys = "PartitionKeys";
|
||||
|
||||
static int32_t logicPartitionNodeToJson(const void* pObj, SJson* pJson) {
|
||||
const SPartitionLogicNode* pNode = (const SPartitionLogicNode*)pObj;
|
||||
|
||||
int32_t code = logicPlanNodeToJson(pObj, pJson);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = nodeListToJson(pJson, jkPartitionLogicPlanPartitionKeys, pNode->pPartitionKeys);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t jsonToLogicPartitionNode(const SJson* pJson, void* pObj) {
|
||||
SPartitionLogicNode* pNode = (SPartitionLogicNode*)pObj;
|
||||
|
||||
int32_t code = jsonToLogicPlanNode(pJson, pObj);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = jsonToNodeList(pJson, jkPartitionLogicPlanPartitionKeys, &pNode->pPartitionKeys);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static const char* jkSubplanIdQueryId = "QueryId";
|
||||
static const char* jkSubplanIdGroupId = "GroupId";
|
||||
static const char* jkSubplanIdSubplanId = "SubplanId";
|
||||
|
||||
static int32_t subplanIdToJson(const void* pObj, SJson* pJson) {
|
||||
const SSubplanId* pNode = (const SSubplanId*)pObj;
|
||||
|
||||
int32_t code = tjsonAddIntegerToObject(pJson, jkSubplanIdQueryId, pNode->queryId);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkSubplanIdGroupId, pNode->groupId);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkSubplanIdSubplanId, pNode->subplanId);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t jsonToSubplanId(const SJson* pJson, void* pObj) {
|
||||
SSubplanId* pNode = (SSubplanId*)pObj;
|
||||
|
||||
int32_t code = tjsonGetUBigIntValue(pJson, jkSubplanIdQueryId, &pNode->queryId);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetIntValue(pJson, jkSubplanIdGroupId, &pNode->groupId);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetIntValue(pJson, jkSubplanIdSubplanId, &pNode->subplanId);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static const char* jkEndPointFqdn = "Fqdn";
|
||||
static const char* jkEndPointPort = "Port";
|
||||
|
||||
static int32_t epToJson(const void* pObj, SJson* pJson) {
|
||||
const SEp* pNode = (const SEp*)pObj;
|
||||
|
||||
int32_t code = tjsonAddStringToObject(pJson, jkEndPointFqdn, pNode->fqdn);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkEndPointPort, pNode->port);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t jsonToEp(const SJson* pJson, void* pObj) {
|
||||
SEp* pNode = (SEp*)pObj;
|
||||
|
||||
int32_t code = tjsonGetStringValue(pJson, jkEndPointFqdn, pNode->fqdn);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetSmallIntValue(pJson, jkEndPointPort, &pNode->port);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static const char* jkEpSetInUse = "InUse";
|
||||
static const char* jkEpSetNumOfEps = "NumOfEps";
|
||||
static const char* jkEpSetEps = "Eps";
|
||||
|
||||
static int32_t epSetToJson(const void* pObj, SJson* pJson) {
|
||||
const SEpSet* pNode = (const SEpSet*)pObj;
|
||||
|
||||
int32_t code = tjsonAddIntegerToObject(pJson, jkEpSetInUse, pNode->inUse);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkEpSetNumOfEps, pNode->numOfEps);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddArray(pJson, jkEpSetEps, epToJson, pNode->eps, sizeof(SEp), pNode->numOfEps);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t jsonToEpSet(const SJson* pJson, void* pObj) {
|
||||
SEpSet* pNode = (SEpSet*)pObj;
|
||||
|
||||
int32_t code = tjsonGetTinyIntValue(pJson, jkEpSetInUse, &pNode->inUse);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetTinyIntValue(pJson, jkEpSetNumOfEps, &pNode->numOfEps);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonToArray(pJson, jkEpSetEps, jsonToEp, pNode->eps, sizeof(SEp));
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static const char* jkVgroupInfoVgId = "VgId";
|
||||
static const char* jkVgroupInfoHashBegin = "HashBegin";
|
||||
static const char* jkVgroupInfoHashEnd = "HashEnd";
|
||||
static const char* jkVgroupInfoEpSet = "EpSet";
|
||||
static const char* jkVgroupInfoNumOfTable = "NumOfTable";
|
||||
|
||||
static int32_t vgroupInfoToJson(const void* pObj, SJson* pJson) {
|
||||
const SVgroupInfo* pNode = (const SVgroupInfo*)pObj;
|
||||
|
||||
int32_t code = tjsonAddIntegerToObject(pJson, jkVgroupInfoVgId, pNode->vgId);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkVgroupInfoHashBegin, pNode->hashBegin);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkVgroupInfoHashEnd, pNode->hashEnd);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddObject(pJson, jkVgroupInfoEpSet, epSetToJson, &pNode->epSet);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkVgroupInfoNumOfTable, pNode->numOfTable);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t jsonToVgroupInfo(const SJson* pJson, void* pObj) {
|
||||
SVgroupInfo* pNode = (SVgroupInfo*)pObj;
|
||||
|
||||
int32_t code = tjsonGetIntValue(pJson, jkVgroupInfoVgId, &pNode->vgId);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetUIntValue(pJson, jkVgroupInfoHashBegin, &pNode->hashBegin);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetUIntValue(pJson, jkVgroupInfoHashEnd, &pNode->hashEnd);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonToObject(pJson, jkVgroupInfoEpSet, jsonToEpSet, &pNode->epSet);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetIntValue(pJson, jkVgroupInfoNumOfTable, &pNode->numOfTable);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static const char* jkVgroupsInfoNum = "Num";
|
||||
static const char* jkVgroupsInfoVgroups = "Vgroups";
|
||||
|
||||
static int32_t vgroupsInfoToJson(const void* pObj, SJson* pJson) {
|
||||
const SVgroupsInfo* pNode = (const SVgroupsInfo*)pObj;
|
||||
|
||||
int32_t code = tjsonAddIntegerToObject(pJson, jkVgroupsInfoNum, pNode->numOfVgroups);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddArray(pJson, jkVgroupsInfoVgroups, vgroupInfoToJson, pNode->vgroups, sizeof(SVgroupInfo),
|
||||
pNode->numOfVgroups);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t jsonToVgroupsInfo(const SJson* pJson, void* pObj) {
|
||||
SVgroupsInfo* pNode = (SVgroupsInfo*)pObj;
|
||||
|
||||
int32_t code = tjsonGetIntValue(pJson, jkVgroupsInfoNum, &pNode->numOfVgroups);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonToArray(pJson, jkVgroupsInfoVgroups, jsonToVgroupInfo, pNode->vgroups, sizeof(SVgroupInfo));
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static const char* jkLogicSubplanId = "Id";
|
||||
static const char* jkLogicSubplanChildren = "Children";
|
||||
static const char* jkLogicSubplanRootNode = "RootNode";
|
||||
static const char* jkLogicSubplanType = "SubplanType";
|
||||
static const char* jkLogicSubplanVgroupsSize = "VgroupsSize";
|
||||
static const char* jkLogicSubplanVgroups = "Vgroups";
|
||||
static const char* jkLogicSubplanLevel = "Level";
|
||||
static const char* jkLogicSubplanSplitFlag = "SplitFlag";
|
||||
|
||||
static int32_t logicSubplanToJson(const void* pObj, SJson* pJson) {
|
||||
const SLogicSubplan* pNode = (const SLogicSubplan*)pObj;
|
||||
|
||||
int32_t code = tjsonAddObject(pJson, jkLogicSubplanId, subplanIdToJson, &pNode->id);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = nodeListToJson(pJson, jkLogicSubplanChildren, pNode->pChildren);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddObject(pJson, jkLogicSubplanRootNode, nodeToJson, pNode->pNode);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkLogicSubplanType, pNode->subplanType);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkLogicSubplanVgroupsSize, VGROUPS_INFO_SIZE(pNode->pVgroupList));
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddObject(pJson, jkLogicSubplanVgroups, vgroupsInfoToJson, pNode->pVgroupList);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkLogicSubplanLevel, pNode->level);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkLogicSubplanSplitFlag, pNode->splitFlag);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t jsonToLogicSubplan(const SJson* pJson, void* pObj) {
|
||||
SLogicSubplan* pNode = (SLogicSubplan*)pObj;
|
||||
|
||||
int32_t code = tjsonToObject(pJson, jkLogicSubplanId, jsonToSubplanId, &pNode->id);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = jsonToNodeList(pJson, jkLogicSubplanChildren, &pNode->pChildren);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = jsonToNodeObject(pJson, jkLogicSubplanRootNode, (SNode**)&pNode->pNode);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetNumberValue(pJson, jkLogicSubplanType, pNode->subplanType);
|
||||
}
|
||||
int32_t objSize = 0;
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetIntValue(pJson, jkLogicSubplanVgroupsSize, &objSize);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonMakeObject(pJson, jkLogicSubplanVgroups, jsonToVgroupsInfo, (void**)&pNode->pVgroupList, objSize);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetIntValue(pJson, jkLogicSubplanLevel, &pNode->level);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetIntValue(pJson, jkLogicSubplanSplitFlag, &pNode->splitFlag);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static const char* jkJoinLogicPlanJoinType = "JoinType";
|
||||
static const char* jkJoinLogicPlanOnConditions = "OnConditions";
|
||||
|
||||
|
@ -837,63 +1090,6 @@ static int32_t physiStreamScanNodeToJson(const void* pObj, SJson* pJson) { retur
|
|||
|
||||
static int32_t jsonToPhysiStreamScanNode(const SJson* pJson, void* pObj) { return jsonToPhysiScanNode(pJson, pObj); }
|
||||
|
||||
static const char* jkEndPointFqdn = "Fqdn";
|
||||
static const char* jkEndPointPort = "Port";
|
||||
|
||||
static int32_t epToJson(const void* pObj, SJson* pJson) {
|
||||
const SEp* pNode = (const SEp*)pObj;
|
||||
|
||||
int32_t code = tjsonAddStringToObject(pJson, jkEndPointFqdn, pNode->fqdn);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkEndPointPort, pNode->port);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t jsonToEp(const SJson* pJson, void* pObj) {
|
||||
SEp* pNode = (SEp*)pObj;
|
||||
|
||||
int32_t code = tjsonGetStringValue(pJson, jkEndPointFqdn, pNode->fqdn);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetSmallIntValue(pJson, jkEndPointPort, &pNode->port);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static const char* jkEpSetInUse = "InUse";
|
||||
static const char* jkEpSetNumOfEps = "NumOfEps";
|
||||
static const char* jkEpSetEps = "Eps";
|
||||
|
||||
static int32_t epSetToJson(const void* pObj, SJson* pJson) {
|
||||
const SEpSet* pNode = (const SEpSet*)pObj;
|
||||
|
||||
int32_t code = tjsonAddIntegerToObject(pJson, jkEpSetInUse, pNode->inUse);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkEpSetNumOfEps, pNode->numOfEps);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddArray(pJson, jkEpSetEps, epToJson, pNode->eps, sizeof(SEp), pNode->numOfEps);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t jsonToEpSet(const SJson* pJson, void* pObj) {
|
||||
SEpSet* pNode = (SEpSet*)pObj;
|
||||
|
||||
int32_t code = tjsonGetTinyIntValue(pJson, jkEpSetInUse, &pNode->inUse);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetTinyIntValue(pJson, jkEpSetNumOfEps, &pNode->numOfEps);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonToArray(pJson, jkEpSetEps, jsonToEp, pNode->eps, sizeof(SEp));
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static const char* jkSysTableScanPhysiPlanMnodeEpSet = "MnodeEpSet";
|
||||
static const char* jkSysTableScanPhysiPlanShowRewrite = "ShowRewrite";
|
||||
static const char* jkSysTableScanPhysiPlanAccountId = "AccountId";
|
||||
|
@ -1342,38 +1538,6 @@ static int32_t physiDispatchNodeToJson(const void* pObj, SJson* pJson) { return
|
|||
|
||||
static int32_t jsonToPhysiDispatchNode(const SJson* pJson, void* pObj) { return jsonToPhysicDataSinkNode(pJson, pObj); }
|
||||
|
||||
static const char* jkSubplanIdQueryId = "QueryId";
|
||||
static const char* jkSubplanIdGroupId = "GroupId";
|
||||
static const char* jkSubplanIdSubplanId = "SubplanId";
|
||||
|
||||
static int32_t subplanIdToJson(const void* pObj, SJson* pJson) {
|
||||
const SSubplanId* pNode = (const SSubplanId*)pObj;
|
||||
|
||||
int32_t code = tjsonAddIntegerToObject(pJson, jkSubplanIdQueryId, pNode->queryId);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkSubplanIdGroupId, pNode->groupId);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkSubplanIdSubplanId, pNode->subplanId);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t jsonToSubplanId(const SJson* pJson, void* pObj) {
|
||||
SSubplanId* pNode = (SSubplanId*)pObj;
|
||||
|
||||
int32_t code = tjsonGetUBigIntValue(pJson, jkSubplanIdQueryId, &pNode->queryId);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetIntValue(pJson, jkSubplanIdGroupId, &pNode->groupId);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetIntValue(pJson, jkSubplanIdSubplanId, &pNode->subplanId);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static const char* jkQueryNodeAddrId = "Id";
|
||||
static const char* jkQueryNodeAddrInUse = "InUse";
|
||||
static const char* jkQueryNodeAddrNumOfEps = "NumOfEps";
|
||||
|
@ -1964,78 +2128,6 @@ static int32_t jsonToTableNode(const SJson* pJson, void* pObj) {
|
|||
return code;
|
||||
}
|
||||
|
||||
static const char* jkVgroupInfoVgId = "VgId";
|
||||
static const char* jkVgroupInfoHashBegin = "HashBegin";
|
||||
static const char* jkVgroupInfoHashEnd = "HashEnd";
|
||||
static const char* jkVgroupInfoEpSet = "EpSet";
|
||||
static const char* jkVgroupInfoNumOfTable = "NumOfTable";
|
||||
|
||||
static int32_t vgroupInfoToJson(const void* pObj, SJson* pJson) {
|
||||
const SVgroupInfo* pNode = (const SVgroupInfo*)pObj;
|
||||
|
||||
int32_t code = tjsonAddIntegerToObject(pJson, jkVgroupInfoVgId, pNode->vgId);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkVgroupInfoHashBegin, pNode->hashBegin);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkVgroupInfoHashEnd, pNode->hashEnd);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddObject(pJson, jkVgroupInfoEpSet, epSetToJson, &pNode->epSet);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddIntegerToObject(pJson, jkVgroupInfoNumOfTable, pNode->numOfTable);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t jsonToVgroupInfo(const SJson* pJson, void* pObj) {
|
||||
SVgroupInfo* pNode = (SVgroupInfo*)pObj;
|
||||
|
||||
int32_t code = tjsonGetIntValue(pJson, jkVgroupInfoVgId, &pNode->vgId);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetUIntValue(pJson, jkVgroupInfoHashBegin, &pNode->hashBegin);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetUIntValue(pJson, jkVgroupInfoHashEnd, &pNode->hashEnd);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonToObject(pJson, jkVgroupInfoEpSet, jsonToEpSet, &pNode->epSet);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonGetIntValue(pJson, jkVgroupInfoNumOfTable, &pNode->numOfTable);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static const char* jkVgroupsInfoNum = "Num";
|
||||
static const char* jkVgroupsInfoVgroups = "Vgroups";
|
||||
|
||||
static int32_t vgroupsInfoToJson(const void* pObj, SJson* pJson) {
|
||||
const SVgroupsInfo* pNode = (const SVgroupsInfo*)pObj;
|
||||
|
||||
int32_t code = tjsonAddIntegerToObject(pJson, jkVgroupsInfoNum, pNode->numOfVgroups);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonAddArray(pJson, jkVgroupsInfoVgroups, vgroupInfoToJson, pNode->vgroups, sizeof(SVgroupInfo),
|
||||
pNode->numOfVgroups);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t jsonToVgroupsInfo(const SJson* pJson, void* pObj) {
|
||||
SVgroupsInfo* pNode = (SVgroupsInfo*)pObj;
|
||||
|
||||
int32_t code = tjsonGetIntValue(pJson, jkVgroupsInfoNum, &pNode->numOfVgroups);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = tjsonToArray(pJson, jkVgroupsInfoVgroups, jsonToVgroupInfo, pNode->vgroups, sizeof(SVgroupInfo));
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static const char* jkRealTableMetaSize = "MetaSize";
|
||||
static const char* jkRealTableMeta = "Meta";
|
||||
static const char* jkRealTableVgroupsInfoSize = "VgroupsInfoSize";
|
||||
|
@ -2582,7 +2674,10 @@ static int32_t specificNodeToJson(const void* pObj, SJson* pJson) {
|
|||
break;
|
||||
case QUERY_NODE_LOGIC_PLAN_SORT:
|
||||
return logicSortNodeToJson(pObj, pJson);
|
||||
case QUERY_NODE_LOGIC_PLAN_PARTITION:
|
||||
return logicPartitionNodeToJson(pObj, pJson);
|
||||
case QUERY_NODE_LOGIC_SUBPLAN:
|
||||
return logicSubplanToJson(pObj, pJson);
|
||||
case QUERY_NODE_LOGIC_PLAN:
|
||||
break;
|
||||
case QUERY_NODE_PHYSICAL_PLAN_TAG_SCAN:
|
||||
|
@ -2667,6 +2762,10 @@ static int32_t jsonToSpecificNode(const SJson* pJson, void* pObj) {
|
|||
return jsonToLogicProjectNode(pJson, pObj);
|
||||
case QUERY_NODE_LOGIC_PLAN_SORT:
|
||||
return jsonToLogicSortNode(pJson, pObj);
|
||||
case QUERY_NODE_LOGIC_PLAN_PARTITION:
|
||||
return jsonToLogicPartitionNode(pJson, pObj);
|
||||
case QUERY_NODE_LOGIC_SUBPLAN:
|
||||
return jsonToLogicSubplan(pJson, pObj);
|
||||
case QUERY_NODE_PHYSICAL_PLAN_TAG_SCAN:
|
||||
return jsonToPhysiTagScanNode(pJson, pObj);
|
||||
case QUERY_NODE_PHYSICAL_PLAN_TABLE_SCAN:
|
||||
|
|
|
@ -1090,30 +1090,31 @@ static EDealRes collectColumns(SNode* pNode, void* pContext) {
|
|||
int32_t nodesCollectColumns(SSelectStmt* pSelect, ESqlClause clause, const char* pTableAlias, ECollectColType type,
|
||||
SNodeList** pCols) {
|
||||
if (NULL == pSelect || NULL == pCols) {
|
||||
return TSDB_CODE_SUCCESS;
|
||||
return TSDB_CODE_FAILED;
|
||||
}
|
||||
|
||||
SCollectColumnsCxt cxt = {
|
||||
.errCode = TSDB_CODE_SUCCESS,
|
||||
.pTableAlias = pTableAlias,
|
||||
.collectType = type,
|
||||
.pCols = nodesMakeList(),
|
||||
.pCols = (NULL == *pCols ? nodesMakeList() : *pCols),
|
||||
.pColHash = taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK)};
|
||||
if (NULL == cxt.pCols || NULL == cxt.pColHash) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
*pCols = NULL;
|
||||
nodesWalkSelectStmt(pSelect, clause, collectColumns, &cxt);
|
||||
taosHashCleanup(cxt.pColHash);
|
||||
if (TSDB_CODE_SUCCESS != cxt.errCode) {
|
||||
nodesDestroyList(cxt.pCols);
|
||||
return cxt.errCode;
|
||||
}
|
||||
if (0 == LIST_LENGTH(cxt.pCols)) {
|
||||
if (LIST_LENGTH(cxt.pCols) > 0) {
|
||||
*pCols = cxt.pCols;
|
||||
} else {
|
||||
nodesDestroyList(cxt.pCols);
|
||||
cxt.pCols = NULL;
|
||||
}
|
||||
*pCols = cxt.pCols;
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1134,7 +1135,7 @@ static EDealRes collectFuncs(SNode* pNode, void* pContext) {
|
|||
|
||||
int32_t nodesCollectFuncs(SSelectStmt* pSelect, FFuncClassifier classifier, SNodeList** pFuncs) {
|
||||
if (NULL == pSelect || NULL == pFuncs) {
|
||||
return TSDB_CODE_SUCCESS;
|
||||
return TSDB_CODE_FAILED;
|
||||
}
|
||||
|
||||
SCollectFuncsCxt cxt = {
|
||||
|
@ -1157,6 +1158,46 @@ int32_t nodesCollectFuncs(SSelectStmt* pSelect, FFuncClassifier classifier, SNod
|
|||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
typedef struct SCollectSpecialNodesCxt {
|
||||
int32_t errCode;
|
||||
ENodeType type;
|
||||
SNodeList* pNodes;
|
||||
} SCollectSpecialNodesCxt;
|
||||
|
||||
static EDealRes collectSpecialNodes(SNode* pNode, void* pContext) {
|
||||
SCollectSpecialNodesCxt* pCxt = (SCollectSpecialNodesCxt*)pContext;
|
||||
if (pCxt->type == nodeType(pNode)) {
|
||||
pCxt->errCode = nodesListStrictAppend(pCxt->pNodes, nodesCloneNode(pNode));
|
||||
return (TSDB_CODE_SUCCESS == pCxt->errCode ? DEAL_RES_IGNORE_CHILD : DEAL_RES_ERROR);
|
||||
}
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
|
||||
int32_t nodesCollectSpecialNodes(SSelectStmt* pSelect, ESqlClause clause, ENodeType type, SNodeList** pNodes) {
|
||||
if (NULL == pSelect || NULL == pNodes) {
|
||||
return TSDB_CODE_FAILED;
|
||||
}
|
||||
|
||||
SCollectSpecialNodesCxt cxt = {
|
||||
.errCode = TSDB_CODE_SUCCESS, .type = type, .pNodes = (NULL == *pNodes ? nodesMakeList() : *pNodes)};
|
||||
if (NULL == cxt.pNodes) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
*pNodes = NULL;
|
||||
nodesWalkSelectStmt(pSelect, SQL_CLAUSE_GROUP_BY, collectSpecialNodes, &cxt);
|
||||
if (TSDB_CODE_SUCCESS != cxt.errCode) {
|
||||
nodesDestroyList(cxt.pNodes);
|
||||
return cxt.errCode;
|
||||
}
|
||||
if (LIST_LENGTH(cxt.pNodes) > 0) {
|
||||
*pNodes = cxt.pNodes;
|
||||
} else {
|
||||
nodesDestroyList(cxt.pNodes);
|
||||
}
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
char* getFillModeString(EFillMode mode) {
|
||||
switch (mode) {
|
||||
case FILL_MODE_NONE:
|
||||
|
|
|
@ -30,9 +30,9 @@ typedef struct SAstCreateContext {
|
|||
SParseContext* pQueryCxt;
|
||||
SMsgBuf msgBuf;
|
||||
bool notSupport;
|
||||
bool valid;
|
||||
SNode* pRootNode;
|
||||
int16_t placeholderNo;
|
||||
int32_t errCode;
|
||||
} SAstCreateContext;
|
||||
|
||||
typedef enum EDatabaseOptionType {
|
||||
|
|
|
@ -23,13 +23,12 @@
|
|||
}
|
||||
|
||||
%syntax_error {
|
||||
if (pCxt->valid) {
|
||||
if (TSDB_CODE_SUCCESS == pCxt->errCode) {
|
||||
if(TOKEN.z) {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_SYNTAX_ERROR, TOKEN.z);
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_SYNTAX_ERROR, TOKEN.z);
|
||||
} else {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INCOMPLETE_SQL);
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INCOMPLETE_SQL);
|
||||
}
|
||||
pCxt->valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,8 +41,8 @@
|
|||
%left NK_CONCAT.
|
||||
|
||||
/************************************************ create/alter account *****************************************/
|
||||
cmd ::= CREATE ACCOUNT NK_ID PASS NK_STRING account_options. { pCxt->valid = false; generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_EXPRIE_STATEMENT); }
|
||||
cmd ::= ALTER ACCOUNT NK_ID alter_account_options. { pCxt->valid = false; generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_EXPRIE_STATEMENT); }
|
||||
cmd ::= CREATE ACCOUNT NK_ID PASS NK_STRING account_options. { pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_EXPRIE_STATEMENT); }
|
||||
cmd ::= ALTER ACCOUNT NK_ID alter_account_options. { pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_EXPRIE_STATEMENT); }
|
||||
|
||||
%type account_options { int32_t }
|
||||
%destructor account_options { }
|
||||
|
@ -323,7 +322,7 @@ cmd ::= SHOW QNODES.
|
|||
cmd ::= SHOW FUNCTIONS. { pCxt->pRootNode = createShowStmt(pCxt, QUERY_NODE_SHOW_FUNCTIONS_STMT, NULL, NULL); }
|
||||
cmd ::= SHOW INDEXES FROM table_name_cond(A) from_db_opt(B). { pCxt->pRootNode = createShowStmt(pCxt, QUERY_NODE_SHOW_INDEXES_STMT, A, B); }
|
||||
cmd ::= SHOW STREAMS. { pCxt->pRootNode = createShowStmt(pCxt, QUERY_NODE_SHOW_STREAMS_STMT, NULL, NULL); }
|
||||
cmd ::= SHOW ACCOUNTS. { pCxt->valid = false; generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_EXPRIE_STATEMENT); }
|
||||
cmd ::= SHOW ACCOUNTS. { pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_EXPRIE_STATEMENT); }
|
||||
cmd ::= SHOW APPS. { pCxt->pRootNode = createShowStmt(pCxt, QUERY_NODE_SHOW_APPS_STMT, NULL, NULL); }
|
||||
cmd ::= SHOW CONNECTIONS. { pCxt->pRootNode = createShowStmt(pCxt, QUERY_NODE_SHOW_CONNECTIONS_STMT, NULL, NULL); }
|
||||
cmd ::= SHOW LICENCE. { pCxt->pRootNode = createShowStmt(pCxt, QUERY_NODE_SHOW_LICENCE_STMT, NULL, NULL); }
|
||||
|
@ -491,7 +490,7 @@ signed_literal(A) ::= NK_STRING(B).
|
|||
signed_literal(A) ::= NK_BOOL(B). { A = createValueNode(pCxt, TSDB_DATA_TYPE_BOOL, &B); }
|
||||
signed_literal(A) ::= TIMESTAMP NK_STRING(B). { A = createValueNode(pCxt, TSDB_DATA_TYPE_TIMESTAMP, &B); }
|
||||
signed_literal(A) ::= duration_literal(B). { A = releaseRawExprNode(pCxt, B); }
|
||||
signed_literal(A) ::= NULL. { A = createValueNode(pCxt, TSDB_DATA_TYPE_NULL, NULL); }
|
||||
signed_literal(A) ::= NULL(B). { A = createValueNode(pCxt, TSDB_DATA_TYPE_NULL, &B); }
|
||||
signed_literal(A) ::= literal_func(B). { A = releaseRawExprNode(pCxt, B); }
|
||||
|
||||
%type literal_list { SNodeList* }
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#define CHECK_OUT_OF_MEM(p) \
|
||||
do { \
|
||||
if (NULL == (p)) { \
|
||||
pCxt->valid = false; \
|
||||
pCxt->errCode = TSDB_CODE_OUT_OF_MEMORY; \
|
||||
snprintf(pCxt->pQueryCxt->pMsg, pCxt->pQueryCxt->msgLen, "Out of memory"); \
|
||||
return NULL; \
|
||||
} \
|
||||
|
@ -30,7 +30,7 @@
|
|||
#define CHECK_RAW_EXPR_NODE(node) \
|
||||
do { \
|
||||
if (NULL == (node) || QUERY_NODE_RAW_EXPR != nodeType(node)) { \
|
||||
pCxt->valid = false; \
|
||||
pCxt->errCode = TSDB_CODE_PAR_SYNTAX_ERROR; \
|
||||
return NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
@ -42,9 +42,9 @@ void initAstCreateContext(SParseContext* pParseCxt, SAstCreateContext* pCxt) {
|
|||
pCxt->msgBuf.buf = pParseCxt->pMsg;
|
||||
pCxt->msgBuf.len = pParseCxt->msgLen;
|
||||
pCxt->notSupport = false;
|
||||
pCxt->valid = true;
|
||||
pCxt->pRootNode = NULL;
|
||||
pCxt->placeholderNo = 0;
|
||||
pCxt->errCode = TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static void copyStringFormStringToken(SToken* pToken, char* pBuf, int32_t len) {
|
||||
|
@ -63,42 +63,38 @@ static void trimEscape(SToken* pName) {
|
|||
|
||||
static bool checkUserName(SAstCreateContext* pCxt, SToken* pUserName) {
|
||||
if (NULL == pUserName) {
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = TSDB_CODE_PAR_SYNTAX_ERROR;
|
||||
} else {
|
||||
if (pUserName->n >= TSDB_USER_LEN) {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NAME_OR_PASSWD_TOO_LONG);
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NAME_OR_PASSWD_TOO_LONG);
|
||||
}
|
||||
}
|
||||
if (pCxt->valid) {
|
||||
if (TSDB_CODE_SUCCESS == pCxt->errCode) {
|
||||
trimEscape(pUserName);
|
||||
}
|
||||
return pCxt->valid;
|
||||
return TSDB_CODE_SUCCESS == pCxt->errCode;
|
||||
}
|
||||
|
||||
static bool checkPassword(SAstCreateContext* pCxt, const SToken* pPasswordToken, char* pPassword) {
|
||||
if (NULL == pPasswordToken) {
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = TSDB_CODE_PAR_SYNTAX_ERROR;
|
||||
} else if (pPasswordToken->n >= (TSDB_USET_PASSWORD_LEN - 2)) {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NAME_OR_PASSWD_TOO_LONG);
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NAME_OR_PASSWD_TOO_LONG);
|
||||
} else {
|
||||
strncpy(pPassword, pPasswordToken->z, pPasswordToken->n);
|
||||
strdequote(pPassword);
|
||||
if (strtrim(pPassword) <= 0) {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_PASSWD_EMPTY);
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_PASSWD_EMPTY);
|
||||
}
|
||||
}
|
||||
return pCxt->valid;
|
||||
return TSDB_CODE_SUCCESS == pCxt->errCode;
|
||||
}
|
||||
|
||||
static bool checkAndSplitEndpoint(SAstCreateContext* pCxt, const SToken* pEp, char* pFqdn, int32_t* pPort) {
|
||||
if (NULL == pEp) {
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = TSDB_CODE_PAR_SYNTAX_ERROR;
|
||||
} else if (pEp->n >= TSDB_FQDN_LEN + 2 + 6) { // format 'fqdn:port'
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NAME_OR_PASSWD_TOO_LONG);
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NAME_OR_PASSWD_TOO_LONG);
|
||||
} else {
|
||||
char ep[TSDB_FQDN_LEN + 2 + 6];
|
||||
strncpy(ep, pEp->z, pEp->n);
|
||||
|
@ -106,66 +102,59 @@ static bool checkAndSplitEndpoint(SAstCreateContext* pCxt, const SToken* pEp, ch
|
|||
strtrim(ep);
|
||||
char* pColon = strchr(ep, ':');
|
||||
if (NULL == pColon) {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_ENDPOINT);
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_ENDPOINT);
|
||||
} else {
|
||||
strncpy(pFqdn, ep, pColon - ep);
|
||||
*pPort = strtol(pColon + 1, NULL, 10);
|
||||
if (*pPort >= UINT16_MAX || *pPort <= 0) {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_PORT);
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_PORT);
|
||||
}
|
||||
}
|
||||
}
|
||||
return pCxt->valid;
|
||||
return TSDB_CODE_SUCCESS == pCxt->errCode;
|
||||
}
|
||||
|
||||
static bool checkFqdn(SAstCreateContext* pCxt, const SToken* pFqdn) {
|
||||
if (NULL == pFqdn) {
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = TSDB_CODE_PAR_SYNTAX_ERROR;
|
||||
} else {
|
||||
if (pFqdn->n >= TSDB_FQDN_LEN) {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NAME_OR_PASSWD_TOO_LONG);
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NAME_OR_PASSWD_TOO_LONG);
|
||||
}
|
||||
}
|
||||
return pCxt->valid;
|
||||
return TSDB_CODE_SUCCESS == pCxt->errCode;
|
||||
}
|
||||
|
||||
static bool checkPort(SAstCreateContext* pCxt, const SToken* pPortToken, int32_t* pPort) {
|
||||
if (NULL == pPortToken) {
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = TSDB_CODE_PAR_SYNTAX_ERROR;
|
||||
} else {
|
||||
*pPort = strtol(pPortToken->z, NULL, 10);
|
||||
if (*pPort >= UINT16_MAX || *pPort <= 0) {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_PORT);
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_PORT);
|
||||
}
|
||||
}
|
||||
return pCxt->valid;
|
||||
return TSDB_CODE_SUCCESS == pCxt->errCode;
|
||||
}
|
||||
|
||||
static bool checkDbName(SAstCreateContext* pCxt, SToken* pDbName, bool query) {
|
||||
if (NULL == pDbName) {
|
||||
if (query && NULL == pCxt->pQueryCxt->db) {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_DB_NOT_SPECIFIED);
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_DB_NOT_SPECIFIED);
|
||||
}
|
||||
} else {
|
||||
trimEscape(pDbName);
|
||||
if (pDbName->n >= TSDB_DB_NAME_LEN) {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_IDENTIFIER_NAME, pDbName->z);
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_IDENTIFIER_NAME, pDbName->z);
|
||||
}
|
||||
}
|
||||
return pCxt->valid;
|
||||
return TSDB_CODE_SUCCESS == pCxt->errCode;
|
||||
}
|
||||
|
||||
static bool checkTableName(SAstCreateContext* pCxt, SToken* pTableName) {
|
||||
trimEscape(pTableName);
|
||||
if (NULL != pTableName && pTableName->n >= TSDB_TABLE_NAME_LEN) {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_IDENTIFIER_NAME, pTableName->z);
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_IDENTIFIER_NAME, pTableName->z);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -174,8 +163,7 @@ static bool checkTableName(SAstCreateContext* pCxt, SToken* pTableName) {
|
|||
static bool checkColumnName(SAstCreateContext* pCxt, SToken* pColumnName) {
|
||||
trimEscape(pColumnName);
|
||||
if (NULL != pColumnName && pColumnName->n >= TSDB_COL_NAME_LEN) {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_IDENTIFIER_NAME, pColumnName->z);
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_IDENTIFIER_NAME, pColumnName->z);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -184,8 +172,7 @@ static bool checkColumnName(SAstCreateContext* pCxt, SToken* pColumnName) {
|
|||
static bool checkIndexName(SAstCreateContext* pCxt, SToken* pIndexName) {
|
||||
trimEscape(pIndexName);
|
||||
if (NULL != pIndexName && pIndexName->n >= TSDB_INDEX_NAME_LEN) {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_IDENTIFIER_NAME, pIndexName->z);
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_IDENTIFIER_NAME, pIndexName->z);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -224,7 +211,7 @@ SNode* releaseRawExprNode(SAstCreateContext* pCxt, SNode* pNode) {
|
|||
|
||||
SToken getTokenFromRawExprNode(SAstCreateContext* pCxt, SNode* pNode) {
|
||||
if (NULL == pNode || QUERY_NODE_RAW_EXPR != nodeType(pNode)) {
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = TSDB_CODE_PAR_SYNTAX_ERROR;
|
||||
return nil_token;
|
||||
}
|
||||
SRawExprNode* target = (SRawExprNode*)pNode;
|
||||
|
@ -235,16 +222,12 @@ SToken getTokenFromRawExprNode(SAstCreateContext* pCxt, SNode* pNode) {
|
|||
SNodeList* createNodeList(SAstCreateContext* pCxt, SNode* pNode) {
|
||||
SNodeList* list = nodesMakeList();
|
||||
CHECK_OUT_OF_MEM(list);
|
||||
if (TSDB_CODE_SUCCESS != nodesListAppend(list, pNode)) {
|
||||
pCxt->valid = false;
|
||||
}
|
||||
pCxt->errCode = nodesListAppend(list, pNode);
|
||||
return list;
|
||||
}
|
||||
|
||||
SNodeList* addNodeToList(SAstCreateContext* pCxt, SNodeList* pList, SNode* pNode) {
|
||||
if (TSDB_CODE_SUCCESS != nodesListAppend(pList, pNode)) {
|
||||
pCxt->valid = false;
|
||||
}
|
||||
pCxt->errCode = nodesListAppend(pList, pNode);
|
||||
return pList;
|
||||
}
|
||||
|
||||
|
@ -381,7 +364,7 @@ SNode* createCastFunctionNode(SAstCreateContext* pCxt, SNode* pExpr, SDataType d
|
|||
strcpy(func->functionName, "cast");
|
||||
func->node.resType = dt;
|
||||
if (TSDB_DATA_TYPE_BINARY == dt.type) {
|
||||
func->node.resType.bytes += 2;
|
||||
func->node.resType.bytes += 2;
|
||||
} else if (TSDB_DATA_TYPE_NCHAR == dt.type) {
|
||||
func->node.resType.bytes = func->node.resType.bytes * TSDB_NCHAR_SIZE + 2;
|
||||
}
|
||||
|
@ -531,7 +514,7 @@ SNode* createGroupingSetNode(SAstCreateContext* pCxt, SNode* pNode) {
|
|||
}
|
||||
|
||||
SNode* setProjectionAlias(SAstCreateContext* pCxt, SNode* pNode, const SToken* pAlias) {
|
||||
if (NULL == pNode || !pCxt->valid) {
|
||||
if (NULL == pNode || TSDB_CODE_SUCCESS != pCxt->errCode) {
|
||||
return pNode;
|
||||
}
|
||||
int32_t len = TMIN(sizeof(((SExprNode*)pNode)->aliasName) - 1, pAlias->n);
|
||||
|
@ -995,7 +978,7 @@ static bool needDbShowStmt(ENodeType type) {
|
|||
SNode* createShowStmt(SAstCreateContext* pCxt, ENodeType type, SNode* pDbName, SNode* pTbNamePattern) {
|
||||
if (needDbShowStmt(type) && NULL == pDbName && NULL == pCxt->pQueryCxt->db) {
|
||||
snprintf(pCxt->pQueryCxt->pMsg, pCxt->pQueryCxt->msgLen, "db not specified");
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = TSDB_CODE_PAR_SYNTAX_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
SShowStmt* pStmt = nodesMakeNode(type);
|
||||
|
@ -1256,7 +1239,7 @@ SNode* createCompactStmt(SAstCreateContext* pCxt, SNodeList* pVgroups) {
|
|||
SNode* createCreateFunctionStmt(SAstCreateContext* pCxt, bool ignoreExists, bool aggFunc, const SToken* pFuncName,
|
||||
const SToken* pLibPath, SDataType dataType, int32_t bufSize) {
|
||||
if (pLibPath->n <= 2) {
|
||||
pCxt->valid = false;
|
||||
pCxt->errCode = TSDB_CODE_PAR_SYNTAX_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
SCreateFunctionStmt* pStmt = nodesMakeNode(QUERY_NODE_CREATE_FUNCTION_STMT);
|
||||
|
|
|
@ -53,20 +53,20 @@ int32_t parse(SParseContext* pParseCxt, SQuery** pQuery) {
|
|||
}
|
||||
case TK_NK_ILLEGAL: {
|
||||
snprintf(cxt.pQueryCxt->pMsg, cxt.pQueryCxt->msgLen, "unrecognized token: \"%s\"", t0.z);
|
||||
cxt.valid = false;
|
||||
cxt.errCode = TSDB_CODE_PAR_SYNTAX_ERROR;
|
||||
goto abort_parse;
|
||||
}
|
||||
case TK_NK_HEX:
|
||||
case TK_NK_OCT:
|
||||
case TK_NK_BIN: {
|
||||
snprintf(cxt.pQueryCxt->pMsg, cxt.pQueryCxt->msgLen, "unsupported token: \"%s\"", t0.z);
|
||||
cxt.valid = false;
|
||||
cxt.errCode = TSDB_CODE_PAR_SYNTAX_ERROR;
|
||||
goto abort_parse;
|
||||
}
|
||||
default:
|
||||
Parse(pParser, t0.type, t0, &cxt);
|
||||
// ParseTrace(stdout, "");
|
||||
if (!cxt.valid) {
|
||||
if (TSDB_CODE_SUCCESS != cxt.errCode) {
|
||||
goto abort_parse;
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ int32_t parse(SParseContext* pParseCxt, SQuery** pQuery) {
|
|||
|
||||
abort_parse:
|
||||
ParseFree(pParser, (FFree)taosMemoryFree);
|
||||
if (cxt.valid) {
|
||||
if (TSDB_CODE_SUCCESS == cxt.errCode) {
|
||||
*pQuery = taosMemoryCalloc(1, sizeof(SQuery));
|
||||
if (NULL == *pQuery) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
|
@ -82,5 +82,5 @@ abort_parse:
|
|||
(*pQuery)->pRoot = cxt.pRootNode;
|
||||
(*pQuery)->placeholderNum = cxt.placeholderNo;
|
||||
}
|
||||
return cxt.valid ? TSDB_CODE_SUCCESS : TSDB_CODE_FAILED;
|
||||
return cxt.errCode;
|
||||
}
|
||||
|
|
|
@ -208,6 +208,23 @@ static int32_t calcConstProjections(SCalcConstContext* pCxt, SNodeList* pProject
|
|||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t calcConstGroupBy(SCalcConstContext* pCxt, SSelectStmt* pSelect) {
|
||||
int32_t code = calcConstList(pSelect->pGroupByList);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
SNode* pNode = NULL;
|
||||
FOREACH(pNode, pSelect->pGroupByList) {
|
||||
SNode* pGroupPara = NULL;
|
||||
FOREACH(pGroupPara, ((SGroupingSetNode*)pNode)->pParameterList) {
|
||||
if (QUERY_NODE_VALUE != nodeType(pGroupPara)) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
}
|
||||
DESTORY_LIST(pSelect->pGroupByList);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t calcConstSelect(SCalcConstContext* pCxt, SSelectStmt* pSelect, bool subquery) {
|
||||
int32_t code = calcConstProjections(pCxt, pSelect->pProjectionList, subquery);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
|
|
|
@ -20,12 +20,12 @@
|
|||
#include "functionMgt.h"
|
||||
#include "parUtil.h"
|
||||
#include "scalar.h"
|
||||
#include "systable.h"
|
||||
#include "tglobal.h"
|
||||
#include "ttime.h"
|
||||
#include "systable.h"
|
||||
|
||||
#define generateDealNodeErrMsg(pCxt, code, ...) \
|
||||
(pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, code, ##__VA_ARGS__) ? DEAL_RES_ERROR : DEAL_RES_ERROR)
|
||||
(pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, code, ##__VA_ARGS__), DEAL_RES_ERROR)
|
||||
|
||||
typedef struct STranslateContext {
|
||||
SParseContext* pParseCxt;
|
||||
|
@ -1676,11 +1676,12 @@ static int32_t checkDbRetentionsOption(STranslateContext* pCxt, SNodeList* pRete
|
|||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t checkOptionsDependency(STranslateContext* pCxt, const char* pDbName, SDatabaseOptions* pOptions,
|
||||
bool alter) {
|
||||
static int32_t checkOptionsDependency(STranslateContext* pCxt, const char* pDbName, SDatabaseOptions* pOptions) {
|
||||
int32_t daysPerFile = pOptions->daysPerFile;
|
||||
int32_t daysToKeep0 = pOptions->keep[0];
|
||||
if (alter && (-1 == daysPerFile || -1 == daysToKeep0)) {
|
||||
if (-1 == daysPerFile && -1 == daysToKeep0) {
|
||||
return TSDB_CODE_SUCCESS;
|
||||
} else if (-1 == daysPerFile || -1 == daysToKeep0) {
|
||||
SDbCfgInfo dbCfg;
|
||||
int32_t code = getDBCfg(pCxt, pDbName, &dbCfg);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
|
@ -1695,8 +1696,7 @@ static int32_t checkOptionsDependency(STranslateContext* pCxt, const char* pDbNa
|
|||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t checkDatabaseOptions(STranslateContext* pCxt, const char* pDbName, SDatabaseOptions* pOptions,
|
||||
bool alter) {
|
||||
static int32_t checkDatabaseOptions(STranslateContext* pCxt, const char* pDbName, SDatabaseOptions* pOptions) {
|
||||
int32_t code =
|
||||
checkRangeOption(pCxt, "buffer", pOptions->buffer, TSDB_MIN_BUFFER_PER_VNODE, TSDB_MAX_BUFFER_PER_VNODE);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
|
@ -1753,13 +1753,13 @@ static int32_t checkDatabaseOptions(STranslateContext* pCxt, const char* pDbName
|
|||
code = checkDbRetentionsOption(pCxt, pOptions->pRetentions);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = checkOptionsDependency(pCxt, pDbName, pOptions, alter);
|
||||
code = checkOptionsDependency(pCxt, pDbName, pOptions);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t checkCreateDatabase(STranslateContext* pCxt, SCreateDatabaseStmt* pStmt) {
|
||||
return checkDatabaseOptions(pCxt, pStmt->dbName, pStmt->pOptions, false);
|
||||
return checkDatabaseOptions(pCxt, pStmt->dbName, pStmt->pOptions);
|
||||
}
|
||||
|
||||
typedef int32_t (*FSerializeFunc)(void* pBuf, int32_t bufLen, void* pReq);
|
||||
|
@ -1826,7 +1826,7 @@ static void buildAlterDbReq(STranslateContext* pCxt, SAlterDatabaseStmt* pStmt,
|
|||
}
|
||||
|
||||
static int32_t translateAlterDatabase(STranslateContext* pCxt, SAlterDatabaseStmt* pStmt) {
|
||||
int32_t code = checkDatabaseOptions(pCxt, pStmt->dbName, pStmt->pOptions, true);
|
||||
int32_t code = checkDatabaseOptions(pCxt, pStmt->dbName, pStmt->pOptions);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -3021,11 +3021,11 @@ static YYACTIONTYPE yy_reduce(
|
|||
/********** Begin reduce actions **********************************************/
|
||||
YYMINORTYPE yylhsminor;
|
||||
case 0: /* cmd ::= CREATE ACCOUNT NK_ID PASS NK_STRING account_options */
|
||||
{ pCxt->valid = false; generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_EXPRIE_STATEMENT); }
|
||||
{ pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_EXPRIE_STATEMENT); }
|
||||
yy_destructor(yypParser,232,&yymsp[0].minor);
|
||||
break;
|
||||
case 1: /* cmd ::= ALTER ACCOUNT NK_ID alter_account_options */
|
||||
{ pCxt->valid = false; generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_EXPRIE_STATEMENT); }
|
||||
{ pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_EXPRIE_STATEMENT); }
|
||||
yy_destructor(yypParser,233,&yymsp[0].minor);
|
||||
break;
|
||||
case 2: /* account_options ::= */
|
||||
|
@ -3591,7 +3591,7 @@ static YYACTIONTYPE yy_reduce(
|
|||
{ pCxt->pRootNode = createShowStmt(pCxt, QUERY_NODE_SHOW_STREAMS_STMT, NULL, NULL); }
|
||||
break;
|
||||
case 178: /* cmd ::= SHOW ACCOUNTS */
|
||||
{ pCxt->valid = false; generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_EXPRIE_STATEMENT); }
|
||||
{ pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_EXPRIE_STATEMENT); }
|
||||
break;
|
||||
case 179: /* cmd ::= SHOW APPS */
|
||||
{ pCxt->pRootNode = createShowStmt(pCxt, QUERY_NODE_SHOW_APPS_STMT, NULL, NULL); }
|
||||
|
@ -3902,7 +3902,8 @@ static YYACTIONTYPE yy_reduce(
|
|||
yymsp[0].minor.yy662 = yylhsminor.yy662;
|
||||
break;
|
||||
case 272: /* signed_literal ::= NULL */
|
||||
{ yymsp[0].minor.yy662 = createValueNode(pCxt, TSDB_DATA_TYPE_NULL, NULL); }
|
||||
{ yylhsminor.yy662 = createValueNode(pCxt, TSDB_DATA_TYPE_NULL, &yymsp[0].minor.yy0); }
|
||||
yymsp[0].minor.yy662 = yylhsminor.yy662;
|
||||
break;
|
||||
case 291: /* expression ::= NK_LP expression NK_RP */
|
||||
case 355: /* boolean_primary ::= NK_LP boolean_value_expression NK_RP */ yytestcase(yyruleno==355);
|
||||
|
@ -4352,13 +4353,12 @@ static void yy_syntax_error(
|
|||
#define TOKEN yyminor
|
||||
/************ Begin %syntax_error code ****************************************/
|
||||
|
||||
if (pCxt->valid) {
|
||||
if (TSDB_CODE_SUCCESS == pCxt->errCode) {
|
||||
if(TOKEN.z) {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_SYNTAX_ERROR, TOKEN.z);
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_SYNTAX_ERROR, TOKEN.z);
|
||||
} else {
|
||||
generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INCOMPLETE_SQL);
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INCOMPLETE_SQL);
|
||||
}
|
||||
pCxt->valid = false;
|
||||
}
|
||||
/************ End %syntax_error code ******************************************/
|
||||
ParseARG_STORE /* Suppress warning about unused %extra_argument variable */
|
||||
|
|
|
@ -25,3 +25,8 @@ if(${BUILD_WINGETOPT})
|
|||
)
|
||||
target_link_libraries(parserTest PUBLIC wingetopt)
|
||||
endif()
|
||||
|
||||
add_test(
|
||||
NAME parserTest
|
||||
COMMAND parserTest
|
||||
)
|
||||
|
|
|
@ -155,16 +155,22 @@ int32_t __catalogGetDBVgInfo(SCatalog* pCtg, void* pRpc, const SEpSet* pMgmtEps,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int32_t __catalogGetDBCfg(SCatalog* pCtg, void* pRpc, const SEpSet* pMgmtEps, const char* dbFName, SDbCfgInfo* pDbCfg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void initMetaDataEnv() {
|
||||
mockCatalogService.reset(new MockCatalogService());
|
||||
|
||||
static Stub stub;
|
||||
stub.set(catalogGetHandle, __catalogGetHandle);
|
||||
stub.set(catalogGetTableMeta, __catalogGetTableMeta);
|
||||
stub.set(catalogGetSTableMeta, __catalogGetTableMeta);
|
||||
stub.set(catalogGetTableHashVgroup, __catalogGetTableHashVgroup);
|
||||
stub.set(catalogGetTableDistVgInfo, __catalogGetTableDistVgInfo);
|
||||
stub.set(catalogGetDBVgVersion, __catalogGetDBVgVersion);
|
||||
stub.set(catalogGetDBVgInfo, __catalogGetDBVgInfo);
|
||||
stub.set(catalogGetDBCfg, __catalogGetDBCfg);
|
||||
// {
|
||||
// AddrAny any("libcatalog.so");
|
||||
// std::map<std::string,void*> result;
|
||||
|
|
|
@ -111,9 +111,8 @@ class MockCatalogServiceImpl {
|
|||
}
|
||||
|
||||
int32_t catalogGetTableHashVgroup(const SName* pTableName, SVgroupInfo* vgInfo) const {
|
||||
char db[TSDB_DB_NAME_LEN] = {0};
|
||||
tNameGetDbName(pTableName, db);
|
||||
return copyTableVgroup(db, tNameGetTableName(pTableName), vgInfo);
|
||||
vgInfo->vgId = 1;
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t catalogGetTableDistVgInfo(const SName* pTableName, SArray** vgList) const {
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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 "parTestUtil.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ParserTest {
|
||||
|
||||
class ParserExplainToSyncdbTest : public ParserTestBase {};
|
||||
|
||||
TEST_F(ParserExplainToSyncdbTest, explain) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("explain SELECT * FROM t1");
|
||||
|
||||
run("explain analyze SELECT * FROM t1");
|
||||
|
||||
run("explain analyze verbose true ratio 0.01 SELECT * FROM t1");
|
||||
}
|
||||
|
||||
// todo kill connection
|
||||
// todo kill query
|
||||
// todo kill stream
|
||||
// todo merge vgroup
|
||||
// todo redistribute vgroup
|
||||
// todo reset query cache
|
||||
// todo syncdb
|
||||
|
||||
} // namespace ParserTest
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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 "parTestUtil.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ParserTest {
|
||||
|
||||
class ParserInitialATest : public ParserTestBase {};
|
||||
|
||||
TEST_F(ParserInitialATest, alterAccount) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("alter account ac_wxy pass '123456'", TSDB_CODE_PAR_EXPRIE_STATEMENT);
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialATest, alterDnode) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("alter dnode 1 'resetLog'");
|
||||
|
||||
run("alter dnode 1 'debugFlag' '134'");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialATest, alterDatabase) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("alter database wxy_db cachelast 1 fsync 200 wal 1");
|
||||
}
|
||||
|
||||
// todo alter local
|
||||
// todo alter stable
|
||||
// todo alter table
|
||||
|
||||
TEST_F(ParserInitialATest, alterUser) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("alter user wxy pass '123456'");
|
||||
|
||||
run("alter user wxy privilege 'write'");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialATest, bug001) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("alter database db wal 0 # td-14436", TSDB_CODE_PAR_SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
} // namespace ParserTest
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* 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 "parTestUtil.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ParserTest {
|
||||
|
||||
class ParserInitialCTest : public ParserTestBase {};
|
||||
|
||||
// todo compact
|
||||
|
||||
TEST_F(ParserInitialCTest, createAccount) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create account ac_wxy pass '123456'", TSDB_CODE_PAR_EXPRIE_STATEMENT);
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialCTest, createBnode) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create bnode on dnode 1");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialCTest, createDatabase) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create database wxy_db");
|
||||
|
||||
run("create database if not exists wxy_db "
|
||||
"cachelast 2 "
|
||||
"comp 1 "
|
||||
"days 100 "
|
||||
"fsync 100 "
|
||||
"maxrows 1000 "
|
||||
"minrows 100 "
|
||||
"keep 1440 "
|
||||
"precision 'ms' "
|
||||
"replica 3 "
|
||||
"wal 2 "
|
||||
"vgroups 100 "
|
||||
"single_stable 0 "
|
||||
"retentions 15s:7d,1m:21d,15m:5y");
|
||||
|
||||
run("create database if not exists wxy_db "
|
||||
"days 100m "
|
||||
"keep 1440m,300h,400d ");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialCTest, createDnode) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create dnode abc1 port 7000");
|
||||
|
||||
run("create dnode 1.1.1.1 port 9000");
|
||||
}
|
||||
|
||||
// todo create function
|
||||
|
||||
TEST_F(ParserInitialCTest, createIndexSma) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create sma index index1 on t1 function(max(c1), min(c3 + 10), sum(c4)) INTERVAL(10s)");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialCTest, createMnode) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create mnode on dnode 1");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialCTest, createQnode) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create qnode on dnode 1");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialCTest, createSnode) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create snode on dnode 1");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialCTest, createStable) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create stable t1(ts timestamp, c1 int) TAGS(id int)");
|
||||
|
||||
run("create stable if not exists test.t1("
|
||||
"ts TIMESTAMP, c1 INT, c2 INT UNSIGNED, c3 BIGINT, c4 BIGINT UNSIGNED, c5 FLOAT, c6 DOUBLE, c7 BINARY(20), c8 "
|
||||
"SMALLINT, "
|
||||
"c9 SMALLINT UNSIGNED COMMENT 'test column comment', c10 TINYINT, c11 TINYINT UNSIGNED, c12 BOOL, c13 NCHAR(30), "
|
||||
"c15 VARCHAR(50)) "
|
||||
"TAGS (tsa TIMESTAMP, a1 INT, a2 INT UNSIGNED, a3 BIGINT, a4 BIGINT UNSIGNED, a5 FLOAT, a6 DOUBLE, a7 "
|
||||
"BINARY(20), a8 SMALLINT, "
|
||||
"a9 SMALLINT UNSIGNED COMMENT 'test column comment', a10 TINYINT, a11 TINYINT UNSIGNED, a12 BOOL, a13 NCHAR(30), "
|
||||
"a15 VARCHAR(50)) "
|
||||
"TTL 100 COMMENT 'test create table' SMA(c1, c2, c3) ROLLUP (min) FILE_FACTOR 0.1 DELAY 2");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialCTest, createStream) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create stream s1 as select * from t1");
|
||||
|
||||
run("create stream if not exists s1 as select * from t1");
|
||||
|
||||
run("create stream s1 into st1 as select * from t1");
|
||||
|
||||
run("create stream if not exists s1 trigger window_close watermark 10s into st1 as select * from t1");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialCTest, createTable) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create table t1(ts timestamp, c1 int)");
|
||||
|
||||
run("create table if not exists test.t1("
|
||||
"ts TIMESTAMP, c1 INT, c2 INT UNSIGNED, c3 BIGINT, c4 BIGINT UNSIGNED, c5 FLOAT, c6 DOUBLE, c7 BINARY(20), c8 "
|
||||
"SMALLINT, "
|
||||
"c9 SMALLINT UNSIGNED COMMENT 'test column comment', c10 TINYINT, c11 TINYINT UNSIGNED, c12 BOOL, c13 "
|
||||
"NCHAR(30), "
|
||||
"c15 VARCHAR(50)) "
|
||||
"TTL 100 COMMENT 'test create table' SMA(c1, c2, c3)");
|
||||
|
||||
run("create table if not exists test.t1("
|
||||
"ts TIMESTAMP, c1 INT, c2 INT UNSIGNED, c3 BIGINT, c4 BIGINT UNSIGNED, c5 FLOAT, c6 DOUBLE, c7 BINARY(20), c8 "
|
||||
"SMALLINT, "
|
||||
"c9 SMALLINT UNSIGNED COMMENT 'test column comment', c10 TINYINT, c11 TINYINT UNSIGNED, c12 BOOL, c13 "
|
||||
"NCHAR(30), "
|
||||
"c15 VARCHAR(50)) "
|
||||
"TAGS (tsa TIMESTAMP, a1 INT, a2 INT UNSIGNED, a3 BIGINT, a4 BIGINT UNSIGNED, "
|
||||
"a5 FLOAT, a6 DOUBLE, a7 "
|
||||
"BINARY(20), a8 SMALLINT, "
|
||||
"a9 SMALLINT UNSIGNED COMMENT 'test column comment', a10 "
|
||||
"TINYINT, a11 TINYINT UNSIGNED, a12 BOOL, a13 NCHAR(30), "
|
||||
"a15 VARCHAR(50)) "
|
||||
"TTL 100 COMMENT 'test create "
|
||||
"table' SMA(c1, c2, c3) ROLLUP (min) FILE_FACTOR 0.1 DELAY 2");
|
||||
|
||||
run("create table if not exists t1 using st1 tags(1, 'wxy')");
|
||||
|
||||
run("create table "
|
||||
"if not exists test.t1 using test.st1 (tag1, tag2) tags(1, 'abc') "
|
||||
"if not exists test.t2 using test.st1 (tag1, tag2) tags(2, 'abc') "
|
||||
"if not exists test.t3 using test.st1 (tag1, tag2) tags(3, 'abc') ");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialCTest, createTopic) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create topic tp1 as select * from t1");
|
||||
|
||||
run("create topic if not exists tp1 as select * from t1");
|
||||
|
||||
run("create topic tp1 as test");
|
||||
|
||||
run("create topic if not exists tp1 as test");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialCTest, createUser) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create user wxy pass '123456'");
|
||||
}
|
||||
|
||||
} // namespace ParserTest
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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 "parTestUtil.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ParserTest {
|
||||
|
||||
class ParserInitialDTest : public ParserTestBase {};
|
||||
|
||||
// todo delete
|
||||
// todo desc
|
||||
// todo describe
|
||||
// todo drop account
|
||||
|
||||
TEST_F(ParserInitialDTest, dropBnode) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("drop bnode on dnode 1");
|
||||
}
|
||||
|
||||
// todo drop database
|
||||
// todo drop dnode
|
||||
// todo drop function
|
||||
|
||||
TEST_F(ParserInitialDTest, dropIndex) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("drop index index1 on t1");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialDTest, dropMnode) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("drop mnode on dnode 1");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialDTest, dropQnode) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("drop qnode on dnode 1");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialDTest, dropSnode) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("drop snode on dnode 1");
|
||||
}
|
||||
|
||||
// todo drop stable
|
||||
// todo drop stream
|
||||
// todo drop table
|
||||
|
||||
TEST_F(ParserInitialDTest, dropTopic) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("drop topic tp1");
|
||||
|
||||
run("drop topic if exists tp1");
|
||||
}
|
||||
|
||||
TEST_F(ParserInitialDTest, dropUser) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("drop user wxy");
|
||||
}
|
||||
|
||||
} // namespace ParserTest
|
|
@ -111,6 +111,7 @@ class InsertTest : public Test {
|
|||
cxt_.pMsg = errMagBuf_;
|
||||
cxt_.msgLen = max_err_len;
|
||||
code_ = TSDB_CODE_SUCCESS;
|
||||
res_ = nullptr;
|
||||
}
|
||||
|
||||
SVnodeModifOpStmt* getVnodeModifStmt(SQuery* pQuery) { return (SVnodeModifOpStmt*)pQuery->pRoot; }
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* 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 "parTestUtil.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ParserTest {
|
||||
|
||||
class ParserSelectTest : public ParserTestBase {};
|
||||
|
||||
TEST_F(ParserSelectTest, basic) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select * from t1");
|
||||
|
||||
run("select * from test.t1");
|
||||
|
||||
run("select ts, c1 from t1");
|
||||
|
||||
run("select ts, t.c1 from (select * from t1) t");
|
||||
|
||||
run("select * from t1 tt1, t1 tt2 where tt1.c1 = tt2.c1");
|
||||
}
|
||||
|
||||
TEST_F(ParserSelectTest, constant) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select 123, 20.4, 'abc', \"wxy\", timestamp '2022-02-09 17:30:20', true, false, 10s from t1");
|
||||
|
||||
run("select 1234567890123456789012345678901234567890, 20.1234567890123456789012345678901234567890, 'abc', \"wxy\", "
|
||||
"timestamp '2022-02-09 17:30:20', true, false, 15s from t1");
|
||||
|
||||
run("select 123 + 45 from t1 where 2 - 1");
|
||||
}
|
||||
|
||||
TEST_F(ParserSelectTest, expression) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select ts + 10s, c1 + 10, concat(c2, 'abc') from t1");
|
||||
|
||||
run("select ts > 0, c1 < 20 and c2 = 'qaz' from t1");
|
||||
|
||||
run("select ts > 0, c1 between 10 and 20 and c2 = 'qaz' from t1");
|
||||
}
|
||||
|
||||
TEST_F(ParserSelectTest, condition) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select c1 from t1 where ts in (true, false)");
|
||||
|
||||
run("select * from t1 where c1 > 10 and c1 is not null");
|
||||
}
|
||||
|
||||
TEST_F(ParserSelectTest, pseudoColumn) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select _wstartts, _wendts, count(*) from t1 interval(10s)");
|
||||
}
|
||||
|
||||
TEST_F(ParserSelectTest, multiResFunc) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select last(*), first(*), last_row(*) from t1");
|
||||
|
||||
run("select last(c1, c2), first(t1.*), last_row(c3) from t1");
|
||||
|
||||
run("select last(t2.*), first(t1.c1, t2.*), last_row(t1.*, t2.*) from st1s1 t1, st1s2 t2 where t1.ts = t2.ts");
|
||||
}
|
||||
|
||||
TEST_F(ParserSelectTest, clause) {
|
||||
useDb("root", "test");
|
||||
|
||||
// group by clause
|
||||
run("select count(*) cnt from t1 where c1 > 0");
|
||||
|
||||
run("select count(*), c2 cnt from t1 where c1 > 0 group by c2");
|
||||
|
||||
run("select count(*) cnt from t1 where c1 > 0 group by c2 having count(c1) > 10");
|
||||
|
||||
run("select count(*), c1, c2 + 10, c1 + c2 cnt from t1 where c1 > 0 group by c2, c1");
|
||||
|
||||
run("select count(*), c1 + 10, c2 cnt from t1 where c1 > 0 group by c1 + 10, c2");
|
||||
|
||||
// order by clause
|
||||
run("select count(*) cnt from t1 where c1 > 0 group by c2 order by cnt");
|
||||
|
||||
run("select count(*) cnt from t1 where c1 > 0 group by c2 order by 1");
|
||||
|
||||
// distinct clause
|
||||
// run("select distinct c1, c2 from t1 where c1 > 0 order by c1");
|
||||
|
||||
// run("select distinct c1 + 10, c2 from t1 where c1 > 0 order by c1 + 10, c2");
|
||||
|
||||
// run("select distinct c1 + 10 cc1, c2 cc2 from t1 where c1 > 0 order by cc1, c2");
|
||||
|
||||
// run("select distinct count(c2) from t1 where c1 > 0 group by c1 order by count(c2)");
|
||||
}
|
||||
|
||||
TEST_F(ParserSelectTest, window) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select count(*) from t1 interval(10s)");
|
||||
}
|
||||
|
||||
TEST_F(ParserSelectTest, semanticError) {
|
||||
useDb("root", "test");
|
||||
|
||||
// TSDB_CODE_PAR_INVALID_COLUMN
|
||||
run("select c1, cc1 from t1", TSDB_CODE_PAR_INVALID_COLUMN, PARSER_STAGE_TRANSLATE);
|
||||
|
||||
run("select t1.c1, t1.cc1 from t1", TSDB_CODE_PAR_INVALID_COLUMN, PARSER_STAGE_TRANSLATE);
|
||||
|
||||
// TSDB_CODE_PAR_TABLE_NOT_EXIST
|
||||
run("select * from t10", TSDB_CODE_PAR_TABLE_NOT_EXIST, PARSER_STAGE_TRANSLATE);
|
||||
|
||||
run("select * from test.t10", TSDB_CODE_PAR_TABLE_NOT_EXIST, PARSER_STAGE_TRANSLATE);
|
||||
|
||||
run("select t2.c1 from t1", TSDB_CODE_PAR_TABLE_NOT_EXIST, PARSER_STAGE_TRANSLATE);
|
||||
|
||||
// TSDB_CODE_PAR_AMBIGUOUS_COLUMN
|
||||
run("select c2 from t1 tt1, t1 tt2 where tt1.c1 = tt2.c1", TSDB_CODE_PAR_AMBIGUOUS_COLUMN, PARSER_STAGE_TRANSLATE);
|
||||
|
||||
// TSDB_CODE_PAR_WRONG_VALUE_TYPE
|
||||
run("select timestamp '2010' from t1", TSDB_CODE_PAR_WRONG_VALUE_TYPE, PARSER_STAGE_TRANSLATE);
|
||||
|
||||
// TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION
|
||||
run("select c2 from t1 tt1 join t1 tt2 on count(*) > 0", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION,
|
||||
PARSER_STAGE_TRANSLATE);
|
||||
|
||||
run("select c2 from t1 where count(*) > 0", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION, PARSER_STAGE_TRANSLATE);
|
||||
|
||||
run("select c2 from t1 group by count(*)", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION, PARSER_STAGE_TRANSLATE);
|
||||
|
||||
// TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT
|
||||
run("select c2 from t1 order by 0", TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT, PARSER_STAGE_TRANSLATE);
|
||||
|
||||
run("select c2 from t1 order by 2", TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT, PARSER_STAGE_TRANSLATE);
|
||||
|
||||
// TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION
|
||||
run("select count(*) cnt from t1 having c1 > 0", TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION, PARSER_STAGE_TRANSLATE);
|
||||
|
||||
run("select count(*) cnt from t1 group by c2 having c1 > 0", TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION,
|
||||
PARSER_STAGE_TRANSLATE);
|
||||
|
||||
run("select count(*), c1 cnt from t1 group by c2 having c2 > 0", TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION,
|
||||
PARSER_STAGE_TRANSLATE);
|
||||
|
||||
run("select count(*) cnt from t1 group by c2 having c2 > 0 order by c1", TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION,
|
||||
PARSER_STAGE_TRANSLATE);
|
||||
|
||||
// TSDB_CODE_PAR_NOT_SINGLE_GROUP
|
||||
run("select count(*), c1 from t1", TSDB_CODE_PAR_NOT_SINGLE_GROUP, PARSER_STAGE_TRANSLATE);
|
||||
|
||||
run("select count(*) from t1 order by c1", TSDB_CODE_PAR_NOT_SINGLE_GROUP, PARSER_STAGE_TRANSLATE);
|
||||
|
||||
run("select c1 from t1 order by count(*)", TSDB_CODE_PAR_NOT_SINGLE_GROUP, PARSER_STAGE_TRANSLATE);
|
||||
|
||||
// TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION
|
||||
run("select distinct c1, c2 from t1 where c1 > 0 order by ts", TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION,
|
||||
PARSER_STAGE_TRANSLATE);
|
||||
|
||||
run("select distinct c1 from t1 where c1 > 0 order by count(c2)", TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION,
|
||||
PARSER_STAGE_TRANSLATE);
|
||||
|
||||
run("select distinct c2 from t1 where c1 > 0 order by count(c2)", TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION,
|
||||
PARSER_STAGE_TRANSLATE);
|
||||
}
|
||||
|
||||
} // namespace ParserTest
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* 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 "parTestUtil.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ParserTest {
|
||||
|
||||
class ParserShowToUseTest : public ParserTestBase {};
|
||||
|
||||
// todo show accounts
|
||||
// todo show apps
|
||||
// todo show connections
|
||||
// todo show create database
|
||||
// todo show create stable
|
||||
// todo show create table
|
||||
|
||||
TEST_F(ParserShowToUseTest, showDatabases) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("show databases");
|
||||
}
|
||||
|
||||
TEST_F(ParserShowToUseTest, showDnodes) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("show dnodes");
|
||||
}
|
||||
|
||||
TEST_F(ParserShowToUseTest, showFunctions) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("show functions");
|
||||
}
|
||||
|
||||
// todo show licence
|
||||
|
||||
TEST_F(ParserShowToUseTest, showIndexes) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("show indexes from t1");
|
||||
|
||||
run("show indexes from t1 from test");
|
||||
}
|
||||
|
||||
TEST_F(ParserShowToUseTest, showMnodes) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("show mnodes");
|
||||
}
|
||||
|
||||
TEST_F(ParserShowToUseTest, showModules) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("show modules");
|
||||
}
|
||||
|
||||
TEST_F(ParserShowToUseTest, showQnodes) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("show qnodes");
|
||||
}
|
||||
|
||||
// todo show queries
|
||||
// todo show scores
|
||||
|
||||
TEST_F(ParserShowToUseTest, showStables) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("show stables");
|
||||
|
||||
run("show test.stables");
|
||||
|
||||
run("show stables like 'c%'");
|
||||
|
||||
run("show test.stables like 'c%'");
|
||||
}
|
||||
|
||||
TEST_F(ParserShowToUseTest, showStreams) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("show streams");
|
||||
}
|
||||
|
||||
TEST_F(ParserShowToUseTest, showTables) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("show tables");
|
||||
|
||||
run("show test.tables");
|
||||
|
||||
run("show tables like 'c%'");
|
||||
|
||||
run("show test.tables like 'c%'");
|
||||
}
|
||||
|
||||
// todo show topics
|
||||
|
||||
TEST_F(ParserShowToUseTest, showUsers) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("show users");
|
||||
}
|
||||
|
||||
// todo show variables
|
||||
|
||||
TEST_F(ParserShowToUseTest, showVgroups) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("show vgroups");
|
||||
|
||||
run("show test.vgroups");
|
||||
}
|
||||
|
||||
// todo show vnodes
|
||||
|
||||
// todo split vgroup
|
||||
|
||||
TEST_F(ParserShowToUseTest, useDatabase) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("use wxy_db");
|
||||
}
|
||||
|
||||
} // namespace ParserTest
|
|
@ -30,6 +30,8 @@
|
|||
#include "parTestUtil.h"
|
||||
#include "parToken.h"
|
||||
|
||||
namespace ParserTest {
|
||||
|
||||
class ParserEnv : public testing::Environment {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
|
@ -62,9 +64,11 @@ static void parseArg(int argc, char* argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace ParserTest
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
testing::AddGlobalTestEnvironment(new ParserEnv());
|
||||
testing::AddGlobalTestEnvironment(new ParserTest::ParserEnv());
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
parseArg(argc, argv);
|
||||
ParserTest::parseArg(argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
|
|
@ -23,17 +23,30 @@
|
|||
using namespace std;
|
||||
using namespace testing;
|
||||
|
||||
#define DO_WITH_THROW(func, ...) \
|
||||
do { \
|
||||
int32_t code__ = func(__VA_ARGS__); \
|
||||
if (TSDB_CODE_SUCCESS != code__) { \
|
||||
throw runtime_error("sql:[" + stmtEnv_.sql_ + "] " #func " code:" + to_string(code__) + \
|
||||
", strerror:" + string(tstrerror(code__)) + ", msg:" + string(stmtEnv_.msgBuf_.data())); \
|
||||
} \
|
||||
namespace ParserTest {
|
||||
|
||||
#define DO_WITH_THROW(func, ...) \
|
||||
do { \
|
||||
int32_t code__ = func(__VA_ARGS__); \
|
||||
if (!checkResultCode(#func, code__)) { \
|
||||
if (TSDB_CODE_SUCCESS != code__) { \
|
||||
throw runtime_error("sql:[" + stmtEnv_.sql_ + "] " #func " code:" + to_string(code__) + \
|
||||
", strerror:" + string(tstrerror(code__)) + ", msg:" + string(stmtEnv_.msgBuf_.data())); \
|
||||
} else { \
|
||||
throw runtime_error("sql:[" + stmtEnv_.sql_ + "] " #func " expect " + to_string(stmtEnv_.expect_) + \
|
||||
" actual " + to_string(code__)); \
|
||||
} \
|
||||
} else if (TSDB_CODE_SUCCESS != code__) { \
|
||||
throw TerminateFlag(); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
bool g_isDump = false;
|
||||
|
||||
struct TerminateFlag : public exception {
|
||||
const char* what() const throw() { return "success and terminate"; }
|
||||
};
|
||||
|
||||
class ParserTestBaseImpl {
|
||||
public:
|
||||
void useDb(const string& acctId, const string& db) {
|
||||
|
@ -41,8 +54,8 @@ class ParserTestBaseImpl {
|
|||
caseEnv_.db_ = db;
|
||||
}
|
||||
|
||||
void run(const string& sql) {
|
||||
reset();
|
||||
void run(const string& sql, int32_t expect, ParserStage checkStage) {
|
||||
reset(expect, checkStage);
|
||||
try {
|
||||
SParseContext cxt = {0};
|
||||
setParseContext(sql, &cxt);
|
||||
|
@ -57,6 +70,9 @@ class ParserTestBaseImpl {
|
|||
if (g_isDump) {
|
||||
dump();
|
||||
}
|
||||
} catch (const TerminateFlag& e) {
|
||||
// success and terminate
|
||||
return;
|
||||
} catch (...) {
|
||||
dump();
|
||||
throw;
|
||||
|
@ -72,6 +88,8 @@ class ParserTestBaseImpl {
|
|||
struct stmtEnv {
|
||||
string sql_;
|
||||
array<char, 1024> msgBuf_;
|
||||
int32_t expect_;
|
||||
string checkFunc_;
|
||||
};
|
||||
|
||||
struct stmtRes {
|
||||
|
@ -80,9 +98,34 @@ class ParserTestBaseImpl {
|
|||
string calcConstAst_;
|
||||
};
|
||||
|
||||
void reset() {
|
||||
bool checkResultCode(const string& pFunc, int32_t resultCode) {
|
||||
return !(stmtEnv_.checkFunc_.empty())
|
||||
? (("*" == stmtEnv_.checkFunc_ || stmtEnv_.checkFunc_ == pFunc) ? stmtEnv_.expect_ == resultCode
|
||||
: TSDB_CODE_SUCCESS == resultCode)
|
||||
: true;
|
||||
}
|
||||
|
||||
string stageFunc(ParserStage stage) {
|
||||
switch (stage) {
|
||||
case PARSER_STAGE_PARSE:
|
||||
return "parse";
|
||||
case PARSER_STAGE_TRANSLATE:
|
||||
return "translate";
|
||||
case PARSER_STAGE_CALC_CONST:
|
||||
return "calculateConstant";
|
||||
case PARSER_STAGE_ALL:
|
||||
return "*";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
void reset(int32_t expect, ParserStage checkStage) {
|
||||
stmtEnv_.sql_.clear();
|
||||
stmtEnv_.msgBuf_.fill(0);
|
||||
stmtEnv_.expect_ = expect;
|
||||
stmtEnv_.checkFunc_ = stageFunc(checkStage);
|
||||
|
||||
res_.parsedAst_.clear();
|
||||
res_.translatedAst_.clear();
|
||||
|
@ -146,4 +189,8 @@ ParserTestBase::~ParserTestBase() {}
|
|||
|
||||
void ParserTestBase::useDb(const std::string& acctId, const std::string& db) { impl_->useDb(acctId, db); }
|
||||
|
||||
void ParserTestBase::run(const std::string& sql) { return impl_->run(sql); }
|
||||
void ParserTestBase::run(const std::string& sql, int32_t expect, ParserStage checkStage) {
|
||||
return impl_->run(sql, expect, checkStage);
|
||||
}
|
||||
|
||||
} // namespace ParserTest
|
||||
|
|
|
@ -18,15 +18,21 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "taoserror.h"
|
||||
|
||||
namespace ParserTest {
|
||||
|
||||
class ParserTestBaseImpl;
|
||||
|
||||
enum ParserStage { PARSER_STAGE_PARSE, PARSER_STAGE_TRANSLATE, PARSER_STAGE_CALC_CONST, PARSER_STAGE_ALL };
|
||||
|
||||
class ParserTestBase : public testing::Test {
|
||||
public:
|
||||
ParserTestBase();
|
||||
virtual ~ParserTestBase();
|
||||
|
||||
void useDb(const std::string& acctId, const std::string& db);
|
||||
void run(const std::string& sql);
|
||||
void run(const std::string& sql, int32_t expect = TSDB_CODE_SUCCESS, ParserStage checkStage = PARSER_STAGE_ALL);
|
||||
|
||||
private:
|
||||
std::unique_ptr<ParserTestBaseImpl> impl_;
|
||||
|
@ -34,4 +40,6 @@ class ParserTestBase : public testing::Test {
|
|||
|
||||
extern bool g_isDump;
|
||||
|
||||
} // namespace ParserTest
|
||||
|
||||
#endif // PARSER_TEST_UTIL_H
|
||||
|
|
|
@ -1,782 +0,0 @@
|
|||
/*
|
||||
* 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 <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "parInt.h"
|
||||
#include "parTestUtil.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace testing;
|
||||
|
||||
class ParserTest : public Test {
|
||||
protected:
|
||||
void setDatabase(const string& acctId, const string& db) {
|
||||
acctId_ = acctId;
|
||||
db_ = db;
|
||||
}
|
||||
|
||||
void bind(const char* sql) {
|
||||
reset();
|
||||
cxt_.acctId = atoi(acctId_.c_str());
|
||||
cxt_.db = db_.c_str();
|
||||
sqlBuf_ = string(sql);
|
||||
transform(sqlBuf_.begin(), sqlBuf_.end(), sqlBuf_.begin(), ::tolower);
|
||||
cxt_.sqlLen = strlen(sql);
|
||||
cxt_.pSql = sqlBuf_.c_str();
|
||||
}
|
||||
|
||||
bool run(int32_t parseCode = TSDB_CODE_SUCCESS, int32_t translateCode = TSDB_CODE_SUCCESS) {
|
||||
query_ = nullptr;
|
||||
bool res = runImpl(parseCode, translateCode);
|
||||
qDestroyQuery(query_);
|
||||
if (!res || g_isDump) {
|
||||
dump();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
static const int max_err_len = 1024;
|
||||
|
||||
bool runImpl(int32_t parseCode, int32_t translateCode) {
|
||||
int32_t code = parse(&cxt_, &query_);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
parseErrStr_ = string("code:") + tstrerror(code) + string(", msg:") + errMagBuf_;
|
||||
return (code == parseCode);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS != parseCode) {
|
||||
return false;
|
||||
}
|
||||
parsedAstStr_ = toString(query_->pRoot);
|
||||
code = translate(&cxt_, query_);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
translateErrStr_ = string("code:") + tstrerror(code) + string(", msg:") + errMagBuf_;
|
||||
return (code == translateCode);
|
||||
}
|
||||
translatedAstStr_ = toString(query_->pRoot);
|
||||
code = calculateConstant(&cxt_, query_);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
calcConstErrStr_ = string("code:") + tstrerror(code) + string(", msg:") + errMagBuf_;
|
||||
return false;
|
||||
}
|
||||
calcConstAstStr_ = toString(query_->pRoot);
|
||||
return (TSDB_CODE_SUCCESS == translateCode);
|
||||
}
|
||||
|
||||
void dump() {
|
||||
cout << "input sql : [" << cxt_.pSql << "]" << endl;
|
||||
if (!parseErrStr_.empty()) {
|
||||
cout << "parse error: " << parseErrStr_ << endl;
|
||||
}
|
||||
if (!parsedAstStr_.empty()) {
|
||||
cout << "parse output: " << endl;
|
||||
cout << parsedAstStr_ << endl;
|
||||
}
|
||||
if (!translateErrStr_.empty()) {
|
||||
cout << "translate error: " << translateErrStr_ << endl;
|
||||
}
|
||||
if (!translatedAstStr_.empty()) {
|
||||
cout << "translate output: " << endl;
|
||||
cout << translatedAstStr_ << endl;
|
||||
}
|
||||
if (!calcConstErrStr_.empty()) {
|
||||
cout << "calculateConstant error: " << calcConstErrStr_ << endl;
|
||||
}
|
||||
if (!calcConstAstStr_.empty()) {
|
||||
cout << "calculateConstant output: " << endl;
|
||||
cout << calcConstAstStr_ << endl;
|
||||
}
|
||||
}
|
||||
|
||||
string toString(const SNode* pRoot, bool format = false) {
|
||||
char* pStr = NULL;
|
||||
int32_t len = 0;
|
||||
int32_t code = nodesNodeToString(pRoot, format, &pStr, &len);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
cout << "sql:[" << cxt_.pSql << "] toString code:" << code << ", strerror:" << tstrerror(code) << endl;
|
||||
throw "nodesNodeToString failed!";
|
||||
}
|
||||
string str(pStr);
|
||||
taosMemoryFreeClear(pStr);
|
||||
return str;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
memset(&cxt_, 0, sizeof(cxt_));
|
||||
memset(errMagBuf_, 0, max_err_len);
|
||||
cxt_.pMsg = errMagBuf_;
|
||||
cxt_.msgLen = max_err_len;
|
||||
parseErrStr_.clear();
|
||||
parsedAstStr_.clear();
|
||||
translateErrStr_.clear();
|
||||
translatedAstStr_.clear();
|
||||
calcConstErrStr_.clear();
|
||||
calcConstAstStr_.clear();
|
||||
}
|
||||
|
||||
string acctId_;
|
||||
string db_;
|
||||
char errMagBuf_[max_err_len];
|
||||
string sqlBuf_;
|
||||
SParseContext cxt_;
|
||||
SQuery* query_;
|
||||
string parseErrStr_;
|
||||
string parsedAstStr_;
|
||||
string translateErrStr_;
|
||||
string translatedAstStr_;
|
||||
string calcConstErrStr_;
|
||||
string calcConstAstStr_;
|
||||
};
|
||||
|
||||
TEST_F(ParserTest, createAccount) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("create account ac_wxy pass '123456'");
|
||||
ASSERT_TRUE(run(TSDB_CODE_PAR_EXPRIE_STATEMENT));
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, alterAccount) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("alter account ac_wxy pass '123456'");
|
||||
ASSERT_TRUE(run(TSDB_CODE_PAR_EXPRIE_STATEMENT));
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, createUser) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("create user wxy pass '123456'");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, alterUser) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("alter user wxy pass '123456'");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("alter user wxy privilege 'write'");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, dropUser) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("drop user wxy");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, selectSimple) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT * FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT * FROM test.t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT ts, c1 FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT ts, t.c1 FROM (SELECT * FROM t1) t");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT * FROM t1 tt1, t1 tt2 WHERE tt1.c1 = tt2.c1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, selectConstant) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT 123, 20.4, 'abc', \"wxy\", TIMESTAMP '2022-02-09 17:30:20', true, false, 10s FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind(
|
||||
"SELECT 1234567890123456789012345678901234567890, 20.1234567890123456789012345678901234567890, 'abc', \"wxy\", "
|
||||
"TIMESTAMP '2022-02-09 17:30:20', true, false, 15s FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT 123 + 45 FROM t1 where 2 - 1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, selectExpression) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT ts + 10s, c1 + 10, concat(c2, 'abc') FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT ts > 0, c1 < 20 AND c2 = 'qaz' FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT ts > 0, c1 BETWEEN 10 AND 20 AND c2 = 'qaz' FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, selectCondition) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT c1 FROM t1 where ts in (true, false)");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT * FROM t1 where c1 > 10 and c1 is not null");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, selectPseudoColumn) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT _wstartts, _wendts, count(*) FROM t1 interval(10s)");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, selectMultiResFunc) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
// bind("SELECT last(*), first(*), last_row(*) FROM t1");
|
||||
// ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT last(c1, c2), first(t1.*), last_row(c3) FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT last(t2.*), first(t1.c1, t2.*), last_row(t1.*, t2.*) FROM st1s1 t1, st1s2 t2 where t1.ts = t2.ts");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, selectClause) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
// GROUP BY clause
|
||||
bind("SELECT count(*) cnt FROM t1 WHERE c1 > 0");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT count(*), c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c2");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT count(*) cnt FROM t1 WHERE c1 > 0 GROUP BY c2 HAVING count(c1) > 10");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT count(*), c1, c2 + 10, c1 + c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c2, c1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT count(*), c1 + 10, c2 cnt FROM t1 WHERE c1 > 0 GROUP BY c1 + 10, c2");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
// ORDER BY clause
|
||||
bind("SELECT count(*) cnt FROM t1 WHERE c1 > 0 GROUP BY c2 ORDER BY cnt");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT count(*) cnt FROM t1 WHERE c1 > 0 GROUP BY c2 ORDER BY 1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
// DISTINCT clause
|
||||
bind("SELECT DISTINCT c1, c2 FROM t1 WHERE c1 > 0 ORDER BY c1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT DISTINCT c1 + 10, c2 FROM t1 WHERE c1 > 0 ORDER BY c1 + 10, c2");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT DISTINCT c1 + 10 cc1, c2 cc2 FROM t1 WHERE c1 > 0 ORDER BY cc1, c2");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT DISTINCT count(c2) FROM t1 WHERE c1 > 0 GROUP BY c1 ORDER BY count(c2)");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, selectWindow) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT count(*) FROM t1 interval(10s)");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, selectSyntaxError) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECTT * FROM t1");
|
||||
ASSERT_TRUE(run(TSDB_CODE_FAILED));
|
||||
|
||||
bind("SELECT *");
|
||||
ASSERT_TRUE(run(TSDB_CODE_FAILED));
|
||||
|
||||
bind("SELECT *, * FROM test.t1");
|
||||
ASSERT_TRUE(run(TSDB_CODE_FAILED));
|
||||
|
||||
bind("SELECT * FROM test.t1 t WHER");
|
||||
ASSERT_TRUE(run(TSDB_CODE_FAILED));
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, selectSemanticError) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
// TSDB_CODE_PAR_INVALID_COLUMN
|
||||
bind("SELECT c1, cc1 FROM t1");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_INVALID_COLUMN));
|
||||
|
||||
bind("SELECT t1.c1, t1.cc1 FROM t1");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_INVALID_COLUMN));
|
||||
|
||||
// TSDB_CODE_PAR_TABLE_NOT_EXIST
|
||||
bind("SELECT * FROM t10");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_TABLE_NOT_EXIST));
|
||||
|
||||
bind("SELECT * FROM test.t10");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_TABLE_NOT_EXIST));
|
||||
|
||||
bind("SELECT t2.c1 FROM t1");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_TABLE_NOT_EXIST));
|
||||
|
||||
// TSDB_CODE_PAR_AMBIGUOUS_COLUMN
|
||||
bind("SELECT c2 FROM t1 tt1, t1 tt2 WHERE tt1.c1 = tt2.c1");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_AMBIGUOUS_COLUMN));
|
||||
|
||||
// TSDB_CODE_PAR_WRONG_VALUE_TYPE
|
||||
bind("SELECT 10n FROM t1");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_WRONG_VALUE_TYPE));
|
||||
|
||||
bind("SELECT TIMESTAMP '2010' FROM t1");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_WRONG_VALUE_TYPE));
|
||||
|
||||
// TSDB_CODE_PAR_INVALID_FUNTION
|
||||
bind("SELECT cnt(*) FROM t1");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_FUNC_INVALID_FUNTION));
|
||||
|
||||
// TSDB_CODE_PAR_FUNTION_PARA_NUM
|
||||
// TSDB_CODE_PAR_FUNTION_PARA_TYPE
|
||||
|
||||
// TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION
|
||||
bind("SELECT c2 FROM t1 tt1 JOIN t1 tt2 ON count(*) > 0");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION));
|
||||
|
||||
bind("SELECT c2 FROM t1 where count(*) > 0");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION));
|
||||
|
||||
bind("SELECT c2 FROM t1 GROUP BY count(*)");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION));
|
||||
|
||||
// TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT
|
||||
bind("SELECT c2 FROM t1 ORDER BY 0");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT));
|
||||
|
||||
bind("SELECT c2 FROM t1 ORDER BY 2");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT));
|
||||
|
||||
// TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION
|
||||
bind("SELECT count(*) cnt FROM t1 HAVING c1 > 0");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION));
|
||||
|
||||
bind("SELECT count(*) cnt FROM t1 GROUP BY c2 HAVING c1 > 0");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION));
|
||||
|
||||
bind("SELECT count(*), c1 cnt FROM t1 GROUP BY c2 HAVING c2 > 0");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION));
|
||||
|
||||
bind("SELECT count(*) cnt FROM t1 GROUP BY c2 HAVING c2 > 0 ORDER BY c1");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_GROUPBY_LACK_EXPRESSION));
|
||||
|
||||
// TSDB_CODE_PAR_NOT_SINGLE_GROUP
|
||||
bind("SELECT count(*), c1 FROM t1");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SINGLE_GROUP));
|
||||
|
||||
bind("SELECT count(*) FROM t1 ORDER BY c1");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SINGLE_GROUP));
|
||||
|
||||
bind("SELECT c1 FROM t1 ORDER BY count(*)");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SINGLE_GROUP));
|
||||
|
||||
// TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION
|
||||
bind("SELECT DISTINCT c1, c2 FROM t1 WHERE c1 > 0 ORDER BY ts");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION));
|
||||
|
||||
bind("SELECT DISTINCT c1 FROM t1 WHERE c1 > 0 ORDER BY count(c2)");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION));
|
||||
|
||||
bind("SELECT DISTINCT c2 FROM t1 WHERE c1 > 0 ORDER BY count(c2)");
|
||||
ASSERT_TRUE(run(TSDB_CODE_SUCCESS, TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION));
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, showUsers) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("show users");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, createDnode) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("create dnode abc1 port 7000");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("create dnode 1.1.1.1 port 9000");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, showDnodes) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("show dnodes");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, alterDnode) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("alter dnode 1 'resetLog'");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("alter dnode 1 'debugFlag' '134'");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, createDatabase) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("create database wxy_db");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind(
|
||||
"create database if not exists wxy_db "
|
||||
"BLOCKS 100 "
|
||||
"CACHE 100 "
|
||||
"CACHELAST 2 "
|
||||
"COMP 1 "
|
||||
"DAYS 100 "
|
||||
"FSYNC 100 "
|
||||
"MAXROWS 1000 "
|
||||
"MINROWS 100 "
|
||||
"KEEP 100 "
|
||||
"PRECISION 'ms' "
|
||||
"QUORUM 1 "
|
||||
"REPLICA 3 "
|
||||
"TTL 100 "
|
||||
"WAL 2 "
|
||||
"VGROUPS 100 "
|
||||
"SINGLE_STABLE 0 "
|
||||
"STREAM_MODE 1 "
|
||||
"RETENTIONS '15s:7d,1m:21d,15m:5y'");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind(
|
||||
"create database if not exists wxy_db "
|
||||
"DAYS 100m "
|
||||
"KEEP 200m,300h,400d ");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, alterDatabase) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("alter database wxy_db BLOCKS 200");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind(
|
||||
"alter database wxy_db "
|
||||
"BLOCKS 200 "
|
||||
"CACHELAST 1 "
|
||||
"FSYNC 200 "
|
||||
"KEEP 200 "
|
||||
"QUORUM 2 "
|
||||
"WAL 1 ");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, showDatabase) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("show databases");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, useDatabase) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("use wxy_db");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, createTable) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("create table t1(ts timestamp, c1 int)");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind(
|
||||
"create table if not exists test.t1("
|
||||
"ts TIMESTAMP, c1 INT, c2 INT UNSIGNED, c3 BIGINT, c4 BIGINT UNSIGNED, c5 FLOAT, c6 DOUBLE, c7 BINARY(20), c8 "
|
||||
"SMALLINT, "
|
||||
"c9 SMALLINT UNSIGNED COMMENT 'test column comment', c10 TINYINT, c11 TINYINT UNSIGNED, c12 BOOL, c13 NCHAR(30), "
|
||||
"c14 JSON, c15 VARCHAR(50)) "
|
||||
"KEEP 100 TTL 100 COMMENT 'test create table' SMA(c1, c2, c3)");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind(
|
||||
"create table if not exists test.t1("
|
||||
"ts TIMESTAMP, c1 INT, c2 INT UNSIGNED, c3 BIGINT, c4 BIGINT UNSIGNED, c5 FLOAT, c6 DOUBLE, c7 BINARY(20), c8 "
|
||||
"SMALLINT, "
|
||||
"c9 SMALLINT UNSIGNED COMMENT 'test column comment', c10 TINYINT, c11 TINYINT UNSIGNED, c12 BOOL, c13 NCHAR(30), "
|
||||
"c14 JSON, c15 VARCHAR(50)) "
|
||||
"TAGS (tsa TIMESTAMP, a1 INT, a2 INT UNSIGNED, a3 BIGINT, a4 BIGINT UNSIGNED, a5 FLOAT, a6 DOUBLE, a7 "
|
||||
"BINARY(20), a8 SMALLINT, "
|
||||
"a9 SMALLINT UNSIGNED COMMENT 'test column comment', a10 TINYINT, a11 TINYINT UNSIGNED, a12 BOOL, a13 NCHAR(30), "
|
||||
"a14 JSON, a15 VARCHAR(50)) "
|
||||
"KEEP 100 TTL 100 COMMENT 'test create table' SMA(c1, c2, c3) ROLLUP (min) FILE_FACTOR 0.1 DELAY 2");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("create table if not exists t1 using st1 tags(1, 'wxy')");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind(
|
||||
"create table "
|
||||
"if not exists test.t1 using test.st1 (tag1, tag2) tags(1, 'abc') "
|
||||
"if not exists test.t2 using test.st1 (tag1, tag2) tags(2, 'abc') "
|
||||
"if not exists test.t3 using test.st1 (tag1, tag2) tags(3, 'abc') "
|
||||
"if not exists test.t4 using test.st1 (tag1, tag2) tags(3, null) "
|
||||
"if not exists test.t5 using test.st1 (tag1, tag2) tags(null, 'abc') "
|
||||
"if not exists test.t6 using test.st1 (tag1, tag2) tags(null, null)");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("create stable t1(ts timestamp, c1 int) TAGS(id int)");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind(
|
||||
"create stable if not exists test.t1("
|
||||
"ts TIMESTAMP, c1 INT, c2 INT UNSIGNED, c3 BIGINT, c4 BIGINT UNSIGNED, c5 FLOAT, c6 DOUBLE, c7 BINARY(20), c8 "
|
||||
"SMALLINT, "
|
||||
"c9 SMALLINT UNSIGNED COMMENT 'test column comment', c10 TINYINT, c11 TINYINT UNSIGNED, c12 BOOL, c13 NCHAR(30), "
|
||||
"c14 JSON, c15 VARCHAR(50)) "
|
||||
"TAGS (tsa TIMESTAMP, a1 INT, a2 INT UNSIGNED, a3 BIGINT, a4 BIGINT UNSIGNED, a5 FLOAT, a6 DOUBLE, a7 "
|
||||
"BINARY(20), a8 SMALLINT, "
|
||||
"a9 SMALLINT UNSIGNED COMMENT 'test column comment', a10 TINYINT, a11 TINYINT UNSIGNED, a12 BOOL, a13 NCHAR(30), "
|
||||
"a14 JSON, a15 VARCHAR(50)) "
|
||||
"KEEP 100 TTL 100 COMMENT 'test create table' SMA(c1, c2, c3) ROLLUP (min) FILE_FACTOR 0.1 DELAY 2");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, showTables) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("show tables");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("show test.tables");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("show tables like 'c%'");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("show test.tables like 'c%'");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, showStables) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("show stables");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("show test.stables");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("show stables like 'c%'");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("show test.stables like 'c%'");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, showVgroups) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("show vgroups");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("show test.vgroups");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, showMnodes) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("show mnodes");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, showModules) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("show modules");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, showQnodes) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("show qnodes");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, showFunctions) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("show functions");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, showIndexes) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("show indexes from t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("show indexes from t1 from test");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, showStreams) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("show streams");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, createSmaIndex) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("create sma index index1 on t1 function(max(c1), min(c3 + 10), sum(c4)) INTERVAL(10s)");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, dropIndex) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("drop index index1 on t1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, createQnode) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("create qnode on dnode 1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, dropQnode) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("drop qnode on dnode 1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, createBnode) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("create bnode on dnode 1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, dropBnode) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("drop bnode on dnode 1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, createSnode) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("create snode on dnode 1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, dropSnode) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("drop snode on dnode 1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, createMnode) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("create mnode on dnode 1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, dropMnode) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("drop mnode on dnode 1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, createTopic) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("create topic tp1 as select * from t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("create topic if not exists tp1 as select * from t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("create topic tp1 as test");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("create topic if not exists tp1 as test");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, dropTopic) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("drop topic tp1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("drop topic if exists tp1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, createStream) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("create stream s1 as select * from t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("create stream if not exists s1 as select * from t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("create stream s1 into st1 as select * from t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("create stream if not exists s1 trigger window_close watermark 10s into st1 as select * from t1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, explain) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("explain SELECT * FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("explain analyze SELECT * FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("explain analyze verbose true ratio 0.01 SELECT * FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
|
@ -748,10 +748,10 @@ static int32_t createSelectLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSele
|
|||
SLogicNode* pRoot = NULL;
|
||||
int32_t code = createLogicNodeByTable(pCxt, pSelect, pSelect->pFromTable, &pRoot);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = createChildLogicNode(pCxt, pSelect, createWindowLogicNode, &pRoot);
|
||||
code = createChildLogicNode(pCxt, pSelect, createPartitionLogicNode, &pRoot);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = createChildLogicNode(pCxt, pSelect, createPartitionLogicNode, &pRoot);
|
||||
code = createChildLogicNode(pCxt, pSelect, createWindowLogicNode, &pRoot);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = createChildLogicNode(pCxt, pSelect, createAggLogicNode, &pRoot);
|
||||
|
|
|
@ -520,6 +520,7 @@ static int32_t cpdPushCondToChild(SOptimizeContext* pCxt, SLogicNode* pChild, SN
|
|||
default:
|
||||
break;
|
||||
}
|
||||
planError("cpdPushCondToChild failed, invalid logic plan node %s", nodesNodeName(nodeType(pChild)));
|
||||
return TSDB_CODE_PLAN_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -272,6 +272,7 @@ static EDealRes doSetSlotId(SNode* pNode, void* pContext) {
|
|||
}
|
||||
// pIndex is definitely not NULL, otherwise it is a bug
|
||||
if (NULL == pIndex) {
|
||||
planError("doSetSlotId failed, invalid slot name %s", name);
|
||||
pCxt->errCode = TSDB_CODE_PLAN_INTERNAL_ERROR;
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
|
@ -435,12 +436,15 @@ static void vgroupInfoToNodeAddr(const SVgroupInfo* vg, SQueryNodeAddr* pNodeAdd
|
|||
pNodeAddr->epSet = vg->epSet;
|
||||
}
|
||||
|
||||
static int32_t createTagScanPhysiNode(SPhysiPlanContext* pCxt, SScanLogicNode* pScanLogicNode, SPhysiNode** pPhyNode) {
|
||||
static int32_t createTagScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubplan, SScanLogicNode* pScanLogicNode,
|
||||
SPhysiNode** pPhyNode) {
|
||||
STagScanPhysiNode* pTagScan = (STagScanPhysiNode*)makePhysiNode(
|
||||
pCxt, pScanLogicNode->pMeta->tableInfo.precision, (SLogicNode*)pScanLogicNode, QUERY_NODE_PHYSICAL_PLAN_TAG_SCAN);
|
||||
if (NULL == pTagScan) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
vgroupInfoToNodeAddr(pScanLogicNode->pVgroupList->vgroups, &pSubplan->execNode);
|
||||
taosArrayPush(pCxt->pExecNodeList, &pSubplan->execNode);
|
||||
return createScanPhysiNodeFinalize(pCxt, pScanLogicNode, (SScanPhysiNode*)pTagScan, pPhyNode);
|
||||
}
|
||||
|
||||
|
@ -514,7 +518,7 @@ static int32_t createScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubplan,
|
|||
SPhysiNode** pPhyNode) {
|
||||
switch (pScanLogicNode->scanType) {
|
||||
case SCAN_TYPE_TAG:
|
||||
return createTagScanPhysiNode(pCxt, pScanLogicNode, pPhyNode);
|
||||
return createTagScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode);
|
||||
case SCAN_TYPE_TABLE:
|
||||
return createTableScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode);
|
||||
case SCAN_TYPE_SYSTEM_TABLE:
|
||||
|
|
|
@ -31,3 +31,8 @@ if(${BUILD_WINGETOPT})
|
|||
)
|
||||
target_link_libraries(plannerTest PUBLIC wingetopt)
|
||||
endif()
|
||||
|
||||
add_test(
|
||||
NAME plannerTest
|
||||
COMMAND plannerTest
|
||||
)
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 "planTestUtil.h"
|
||||
#include "planner.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PlanBasicTest : public PlannerTestBase {};
|
||||
|
||||
TEST_F(PlanBasicTest, select) {
|
||||
useDb("root", "test");
|
||||
|
||||
// run("select * from t1");
|
||||
// run("select 1 from t1");
|
||||
// run("select * from st1");
|
||||
run("select 1 from st1");
|
||||
}
|
||||
|
||||
TEST_F(PlanBasicTest, where) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select * from t1 where c1 > 10");
|
||||
}
|
||||
|
||||
TEST_F(PlanBasicTest, join) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select t1.c1, t2.c2 from st1s1 t1, st1s2 t2 where t1.ts = t2.ts");
|
||||
run("select t1.c1, t2.c2 from st1s1 t1 join st1s2 t2 on t1.ts = t2.ts");
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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 "planTestUtil.h"
|
||||
#include "planner.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PlanDistinctTest : public PlannerTestBase {};
|
||||
|
||||
TEST_F(PlanDistinctTest, basic) {
|
||||
useDb("root", "test");
|
||||
|
||||
// distinct single col
|
||||
run("select distinct c1 from t1");
|
||||
// distinct col list
|
||||
run("select distinct c1, c2 from t1");
|
||||
}
|
||||
|
||||
TEST_F(PlanDistinctTest, expr) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select distinct c1, c2 + 10 from t1");
|
||||
}
|
||||
|
||||
TEST_F(PlanDistinctTest, withOrderBy) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select distinct c1 + 10 a from t1 order by a");
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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 "planTestUtil.h"
|
||||
#include "planner.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PlanGroupByTest : public PlannerTestBase {};
|
||||
|
||||
TEST_F(PlanGroupByTest, basic) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select count(*) from t1");
|
||||
|
||||
run("select c1, max(c3), min(c3), count(*) from t1 group by c1");
|
||||
|
||||
run("select c1 + c3, c1 + count(*) from t1 where c2 = 'abc' group by c1, c3");
|
||||
|
||||
run("select c1 + c3, sum(c4 * c5) from t1 where concat(c2, 'wwww') = 'abcwww' group by c1 + c3");
|
||||
|
||||
run("select sum(ceil(c1)) from t1 group by ceil(c1)");
|
||||
}
|
||||
|
||||
TEST_F(PlanGroupByTest, withOrderBy) {
|
||||
useDb("root", "test");
|
||||
|
||||
// order by aggfunc
|
||||
run("select count(*), sum(c1) from t1 order by sum(c1)");
|
||||
// order by alias of aggfunc
|
||||
// run("select count(*), sum(c1) a from t1 order by a");
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 "planTestUtil.h"
|
||||
#include "planner.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PlanIntervalTest : public PlannerTestBase {};
|
||||
|
||||
TEST_F(PlanIntervalTest, basic) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select count(*) from t1 interval(10s)");
|
||||
}
|
||||
|
||||
TEST_F(PlanIntervalTest, pseudoCol) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select _wstartts, _wduration, _wendts, count(*) from t1 interval(10s)");
|
||||
}
|
||||
|
||||
TEST_F(PlanIntervalTest, fill) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select count(*) from t1 interval(10s) fill(linear)");
|
||||
|
||||
run("select count(*), sum(c1) from t1 interval(10s) fill(value, 10, 20)");
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 "planTestUtil.h"
|
||||
#include "planner.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PlanJoinTest : public PlannerTestBase {};
|
||||
|
||||
TEST_F(PlanJoinTest, basic) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select t1.c1, t2.c2 from st1s1 t1, st1s2 t2 where t1.ts = t2.ts");
|
||||
|
||||
run("select t1.*, t2.* from st1s1 t1, st1s2 t2 where t1.ts = t2.ts");
|
||||
|
||||
// run("select t1.c1, t2.c1 from st1s1 t1 join st1s2 t2 on t1.ts = t2.ts where t1.c1 > t2.c1 and t1.c2 = 'abc' and "
|
||||
// "t2.c2 = 'qwe'");
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 "planTestUtil.h"
|
||||
#include "planner.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PlanLimitTest : public PlannerTestBase {};
|
||||
|
||||
TEST_F(PlanLimitTest, limit) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select * from t1 limit 2");
|
||||
|
||||
run("select * from t1 limit 5 offset 2");
|
||||
|
||||
run("select * from t1 limit 2, 5");
|
||||
}
|
||||
|
||||
TEST_F(PlanLimitTest, slimit) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select * from t1 partition by c1 slimit 2");
|
||||
|
||||
run("select * from t1 partition by c1 slimit 5 soffset 2");
|
||||
|
||||
run("select * from t1 partition by c1 slimit 2, 5");
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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 "planTestUtil.h"
|
||||
#include "planner.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PlanOrderByTest : public PlannerTestBase {};
|
||||
|
||||
TEST_F(PlanOrderByTest, basic) {
|
||||
useDb("root", "test");
|
||||
|
||||
// order by key is in the projection list
|
||||
run("select c1 from t1 order by c1");
|
||||
// order by key is not in the projection list
|
||||
run("select c1 from t1 order by c2");
|
||||
}
|
||||
|
||||
TEST_F(PlanOrderByTest, expr) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select * from t1 order by c1 + 10, c2");
|
||||
}
|
||||
|
||||
TEST_F(PlanOrderByTest, nullsOrder) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select * from t1 order by c1 desc nulls first");
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 "planTestUtil.h"
|
||||
#include "planner.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PlanOtherTest : public PlannerTestBase {};
|
||||
|
||||
TEST_F(PlanOtherTest, createTopic) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create topic tp as SELECT * FROM st1");
|
||||
}
|
||||
|
||||
TEST_F(PlanOtherTest, createStream) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create stream if not exists s1 trigger window_close watermark 10s into st1 as select count(*) from t1 "
|
||||
"interval(10s)");
|
||||
}
|
||||
|
||||
TEST_F(PlanOtherTest, createSmaIndex) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create sma index index1 on t1 function(max(c1), min(c3 + 10), sum(c4)) interval(10s)");
|
||||
}
|
||||
|
||||
TEST_F(PlanOtherTest, explain) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("explain SELECT * FROM t1");
|
||||
|
||||
run("explain analyze SELECT * FROM t1");
|
||||
|
||||
run("explain analyze verbose true ratio 0.01 SELECT * FROM t1");
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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 "planTestUtil.h"
|
||||
#include "planner.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PlanPartitionByTest : public PlannerTestBase {};
|
||||
|
||||
TEST_F(PlanPartitionByTest, basic) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select * from t1 partition by c1");
|
||||
}
|
||||
|
||||
TEST_F(PlanPartitionByTest, withAggFunc) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select count(*) from t1 partition by c1");
|
||||
}
|
||||
|
||||
TEST_F(PlanPartitionByTest, withInterval) {
|
||||
useDb("root", "test");
|
||||
|
||||
// normal/child table
|
||||
run("select count(*) from t1 partition by c1 interval(10s)");
|
||||
// super table
|
||||
run("select count(*) from st1 partition by tag1, tag2 interval(10s)");
|
||||
}
|
||||
|
||||
TEST_F(PlanPartitionByTest, withGroupBy) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select count(*) from t1 partition by c1 group by c2");
|
||||
}
|
|
@ -13,14 +13,15 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "parTestUtil.h"
|
||||
#include "planTestUtil.h"
|
||||
#include "planner.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class ParserAlterTest : public ParserTestBase {};
|
||||
class PlanSessionTest : public PlannerTestBase {};
|
||||
|
||||
TEST_F(ParserAlterTest, stmt) {
|
||||
TEST_F(PlanSessionTest, basic) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("create database db1");
|
||||
run("select count(*) from t1 session(ts, 10s)");
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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 "planTestUtil.h"
|
||||
#include "planner.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PlanStateTest : public PlannerTestBase {};
|
||||
|
||||
TEST_F(PlanStateTest, basic) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select count(*) from t1 state_window(c1)");
|
||||
}
|
||||
|
||||
TEST_F(PlanStateTest, stateExpr) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select count(*) from t1 state_window(c1 + 10)");
|
||||
}
|
|
@ -42,13 +42,13 @@ class PlanStmtTest : public PlannerTestBase {
|
|||
// todo
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
TAOS_MULTI_BIND* pBindParams_;
|
||||
int32_t paramNo_;
|
||||
int32_t paramNo_;
|
||||
};
|
||||
|
||||
TEST_F(PlanStmtTest, stmt) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("SELECT * FROM t1 where c1 = ?");
|
||||
run("select * from t1 where c1 = ?");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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 "planTestUtil.h"
|
||||
#include "planner.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PlanSubqeuryTest : public PlannerTestBase {};
|
||||
|
||||
TEST_F(PlanSubqeuryTest, basic) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select * from (select * from t1)");
|
||||
}
|
||||
|
||||
TEST_F(PlanSubqeuryTest, doubleGroupBy) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("select count(*) from (select c1 + c3 a, c1 + count(*) b from t1 where c2 = 'abc' group by c1, c3) where a > 100 "
|
||||
"group by b");
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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 "planTestUtil.h"
|
||||
#include "planner.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PlanSysTableTest : public PlannerTestBase {};
|
||||
|
||||
TEST_F(PlanSysTableTest, show) {
|
||||
useDb("root", "test");
|
||||
|
||||
run("show tables");
|
||||
run("show stables");
|
||||
}
|
||||
|
||||
TEST_F(PlanSysTableTest, information) {
|
||||
useDb("root", "information_schema");
|
||||
|
||||
run("show tables");
|
||||
}
|
|
@ -106,6 +106,7 @@ class PlannerTestBaseImpl {
|
|||
res_.splitLogicPlan_.clear();
|
||||
res_.scaledLogicPlan_.clear();
|
||||
res_.physiPlan_.clear();
|
||||
res_.physiSubplans_.clear();
|
||||
}
|
||||
|
||||
void dump() {
|
||||
|
|
|
@ -1,398 +0,0 @@
|
|||
/*
|
||||
* 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 <algorithm>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "cmdnodes.h"
|
||||
#include "parser.h"
|
||||
#include "planInt.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace testing;
|
||||
|
||||
class PlannerTest : public Test {
|
||||
protected:
|
||||
void setDatabase(const string& acctId, const string& db) {
|
||||
acctId_ = acctId;
|
||||
db_ = db;
|
||||
}
|
||||
|
||||
void bind(const char* sql) {
|
||||
reset();
|
||||
cxt_.acctId = atoi(acctId_.c_str());
|
||||
cxt_.db = db_.c_str();
|
||||
sqlBuf_ = string(sql);
|
||||
transform(sqlBuf_.begin(), sqlBuf_.end(), sqlBuf_.begin(), ::tolower);
|
||||
cxt_.sqlLen = strlen(sql);
|
||||
cxt_.pSql = sqlBuf_.c_str();
|
||||
}
|
||||
|
||||
bool run(bool streamQuery = false) {
|
||||
int32_t code = qParseQuerySql(&cxt_, &query_);
|
||||
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
cout << "sql:[" << cxt_.pSql << "] qParseQuerySql code:" << code << ", strerror:" << tstrerror(code)
|
||||
<< ", msg:" << errMagBuf_ << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
const string syntaxTreeStr = toString(query_->pRoot, false);
|
||||
|
||||
SLogicNode* pLogicNode = nullptr;
|
||||
SPlanContext cxt = {0};
|
||||
cxt.queryId = 1;
|
||||
cxt.acctId = 0;
|
||||
cxt.streamQuery = streamQuery;
|
||||
|
||||
setPlanContext(query_, &cxt);
|
||||
code = createLogicPlan(&cxt, &pLogicNode);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
cout << "sql:[" << cxt_.pSql << "] createLogicPlan code:" << code << ", strerror:" << tstrerror(code) << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
cout << "====================sql : [" << cxt_.pSql << "]" << endl;
|
||||
cout << "syntax tree : " << endl;
|
||||
cout << syntaxTreeStr << endl;
|
||||
cout << "unformatted logic plan : " << endl;
|
||||
cout << toString((const SNode*)pLogicNode, false) << endl;
|
||||
|
||||
code = optimizeLogicPlan(&cxt, pLogicNode);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
cout << "sql:[" << cxt_.pSql << "] optimizeLogicPlan code:" << code << ", strerror:" << tstrerror(code) << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
SLogicSubplan* pLogicSubplan = nullptr;
|
||||
code = splitLogicPlan(&cxt, pLogicNode, &pLogicSubplan);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
cout << "sql:[" << cxt_.pSql << "] splitLogicPlan code:" << code << ", strerror:" << tstrerror(code) << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
SQueryLogicPlan* pLogicPlan = NULL;
|
||||
code = scaleOutLogicPlan(&cxt, pLogicSubplan, &pLogicPlan);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
cout << "sql:[" << cxt_.pSql << "] createPhysiPlan code:" << code << ", strerror:" << tstrerror(code) << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
SArray* pExecNodeList = taosArrayInit(TARRAY_MIN_SIZE, sizeof(SQueryNodeAddr));
|
||||
code = createPhysiPlan(&cxt, pLogicPlan, &plan_, pExecNodeList);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
cout << "sql:[" << cxt_.pSql << "] createPhysiPlan code:" << code << ", strerror:" << tstrerror(code) << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
cout << "unformatted physical plan : " << endl;
|
||||
cout << toString((const SNode*)plan_, false) << endl;
|
||||
SNode* pNode;
|
||||
FOREACH(pNode, plan_->pSubplans) {
|
||||
SNode* pSubplan;
|
||||
FOREACH(pSubplan, ((SNodeListNode*)pNode)->pNodeList) {
|
||||
cout << "unformatted physical subplan : " << endl;
|
||||
cout << toString(pSubplan, false) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
static const int max_err_len = 1024;
|
||||
|
||||
void setPlanContext(SQuery* pQuery, SPlanContext* pCxt) {
|
||||
if (QUERY_NODE_CREATE_TOPIC_STMT == nodeType(pQuery->pRoot)) {
|
||||
pCxt->pAstRoot = ((SCreateTopicStmt*)pQuery->pRoot)->pQuery;
|
||||
pCxt->topicQuery = true;
|
||||
} else if (QUERY_NODE_CREATE_INDEX_STMT == nodeType(pQuery->pRoot)) {
|
||||
SMCreateSmaReq req = {0};
|
||||
tDeserializeSMCreateSmaReq(pQuery->pCmdMsg->pMsg, pQuery->pCmdMsg->msgLen, &req);
|
||||
nodesStringToNode(req.ast, &pCxt->pAstRoot);
|
||||
pCxt->streamQuery = true;
|
||||
} else if (QUERY_NODE_CREATE_STREAM_STMT == nodeType(pQuery->pRoot)) {
|
||||
SCreateStreamStmt* pStmt = (SCreateStreamStmt*)pQuery->pRoot;
|
||||
pCxt->pAstRoot = pStmt->pQuery;
|
||||
pCxt->streamQuery = true;
|
||||
pCxt->triggerType = pStmt->pOptions->triggerType;
|
||||
pCxt->watermark = (NULL != pStmt->pOptions->pWatermark ? ((SValueNode*)pStmt->pOptions->pWatermark)->datum.i : 0);
|
||||
} else {
|
||||
pCxt->pAstRoot = pQuery->pRoot;
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
memset(&cxt_, 0, sizeof(cxt_));
|
||||
memset(errMagBuf_, 0, max_err_len);
|
||||
cxt_.pMsg = errMagBuf_;
|
||||
cxt_.msgLen = max_err_len;
|
||||
}
|
||||
|
||||
string toString(const SNode* pRoot, bool format = true) {
|
||||
char* pStr = NULL;
|
||||
int32_t len = 0;
|
||||
int32_t code = nodesNodeToString(pRoot, format, &pStr, &len);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
cout << "sql:[" << cxt_.pSql << "] toString code:" << code << ", strerror:" << tstrerror(code) << endl;
|
||||
return string();
|
||||
}
|
||||
string str(pStr);
|
||||
taosMemoryFreeClear(pStr);
|
||||
return str;
|
||||
}
|
||||
|
||||
string acctId_;
|
||||
string db_;
|
||||
char errMagBuf_[max_err_len];
|
||||
string sqlBuf_;
|
||||
SParseContext cxt_;
|
||||
SQuery* query_;
|
||||
SQueryPlan* plan_;
|
||||
};
|
||||
|
||||
TEST_F(PlannerTest, selectBasic) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT * FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, selectConstant) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT 2-1 FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, selectStableBasic) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT * FROM st1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, selectJoin) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT t1.c1, t2.c2 FROM st1s1 t1, st1s2 t2 where t1.ts = t2.ts");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT t1.*, t2.* FROM st1s1 t1, st1s2 t2 where t1.ts = t2.ts");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind(
|
||||
"SELECT t1.c1, t2.c1 FROM st1s1 t1 join st1s2 t2 on t1.ts = t2.ts where t1.c1 > t2.c1 and t1.c2 = 'abc' and "
|
||||
"t2.c2 = 'qwe'");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, selectGroupBy) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT count(*) FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT c1, max(c3), min(c3), count(*) FROM t1 GROUP BY c1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT c1 + c3, c1 + count(*) FROM t1 where c2 = 'abc' GROUP BY c1, c3");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT c1 + c3, sum(c4 * c5) FROM t1 where concat(c2, 'wwww') = 'abcwww' GROUP BY c1 + c3");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT sum(ceil(c1)) FROM t1 GROUP BY ceil(c1)");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, selectSubquery) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind(
|
||||
"SELECT count(*) FROM (SELECT c1 + c3 a, c1 + count(*) b FROM t1 where c2 = 'abc' GROUP BY c1, c3) where a > 100 "
|
||||
"group by b");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, selectInterval) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT count(*) FROM t1 interval(10s)");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT _wstartts, _wduration, _wendts, count(*) FROM t1 interval(10s)");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT count(*) FROM t1 interval(10s) fill(linear)");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT count(*), sum(c1) FROM t1 interval(10s) fill(value, 10, 20)");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, selectSessionWindow) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT count(*) FROM t1 session(ts, 10s)");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, selectStateWindow) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT count(*) FROM t1 state_window(c1)");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT count(*) FROM t1 state_window(c1 + 10)");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, selectPartitionBy) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT * FROM t1 partition by c1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT count(*) FROM t1 partition by c1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT count(*) FROM t1 partition by c1 group by c2");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT count(*) FROM st1 partition by tag1, tag2 interval(10s)");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, selectOrderBy) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT c1 FROM t1 order by c1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT c1 FROM t1 order by c2");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT * FROM t1 order by c1 + 10, c2");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT * FROM t1 order by c1 desc nulls first");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, selectGroupByOrderBy) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("select count(*), sum(c1) from t1 order by sum(c1)");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("select count(*), sum(c1) a from t1 order by a");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, selectDistinct) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT distinct c1 FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT distinct c1, c2 + 10 FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT distinct c1 + 10 a FROM t1 order by a");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, selectLimit) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT * FROM t1 limit 2");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT * FROM t1 limit 5 offset 2");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT * FROM t1 limit 2, 5");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, selectSlimit) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT * FROM t1 partition by c1 slimit 2");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT * FROM t1 partition by c1 slimit 5 soffset 2");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT * FROM t1 partition by c1 slimit 2, 5");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, showTables) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("show tables");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
setDatabase("root", "information_schema");
|
||||
|
||||
bind("show tables");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, showStables) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("show stables");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, createTopic) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("create topic tp as SELECT * FROM st1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, createStream) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind(
|
||||
"create stream if not exists s1 trigger window_close watermark 10s into st1 as select count(*) from t1 "
|
||||
"interval(10s)");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, createSmaIndex) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("create sma index index1 on t1 function(max(c1), min(c3 + 10), sum(c4)) INTERVAL(10s)");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(PlannerTest, explain) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("explain SELECT * FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("explain analyze SELECT * FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("explain analyze verbose true ratio 0.01 SELECT * FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
|
@ -66,7 +66,7 @@
|
|||
|
||||
# --- stable
|
||||
./test.sh -f tsim/stable/disk.sim
|
||||
./test.sh -f tsim/stable/dnode3.sim
|
||||
#./test.sh -f tsim/stable/dnode3.sim
|
||||
./test.sh -f tsim/stable/metrics.sim
|
||||
./test.sh -f tsim/stable/refcount.sim
|
||||
# ./test.sh -f tsim/stable/show.sim
|
||||
|
|
Loading…
Reference in New Issue