diff --git a/include/libs/nodes/nodes.h b/include/libs/nodes/nodes.h index 302e5b03ac..6a0422cd80 100644 --- a/include/libs/nodes/nodes.h +++ b/include/libs/nodes/nodes.h @@ -62,6 +62,7 @@ typedef enum ENodeType { QUERY_NODE_NODE_LIST, QUERY_NODE_FILL, QUERY_NODE_COLUMN_REF, + QUERY_NODE_TARGET, // Only be used in parser module. QUERY_NODE_RAW_EXPR, @@ -93,7 +94,7 @@ typedef struct SListCell { } SListCell; typedef struct SNodeList { - int16_t length; + int32_t length; SListCell* pHead; SListCell* pTail; } SNodeList; @@ -103,6 +104,7 @@ void nodesDestroyNode(SNode* pNode); SNodeList* nodesMakeList(); int32_t nodesListAppend(SNodeList* pList, SNode* pNode); +int32_t nodesListAppendList(SNodeList* pTarget, SNodeList* pSrc); SListCell* nodesListErase(SNodeList* pList, SListCell* pCell); SNode* nodesListGetNode(SNodeList* pList, int32_t index); void nodesDestroyList(SNodeList* pList); diff --git a/include/libs/nodes/plannodes.h b/include/libs/nodes/plannodes.h new file mode 100644 index 0000000000..3668f256eb --- /dev/null +++ b/include/libs/nodes/plannodes.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef _TD_PLANN_NODES_H_ +#define _TD_PLANN_NODES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "querynodes.h" + +typedef struct SLogicNode { + ENodeType type; + int32_t id; + SNodeList* pTargets; // SColumnNode + SNode* pConditions; + SNodeList* pChildren; + struct SLogicNode* pParent; +} SLogicNode; + +typedef struct SScanLogicNode { + SLogicNode node; + SNodeList* pScanCols; + struct STableMeta* pMeta; +} SScanLogicNode; + +typedef struct SJoinLogicNode { + SLogicNode node; + EJoinType joinType; + SNode* pOnConditions; +} SJoinLogicNode; + +typedef struct SFilterLogicNode { + SLogicNode node; +} SFilterLogicNode; + +typedef struct SAggLogicNode { + SLogicNode node; + SNodeList* pGroupKeys; + SNodeList* pAggFuncs; +} SAggLogicNode; + +typedef struct SProjectLogicNode { + SLogicNode node; + SNodeList* pProjections; +} SProjectLogicNode; + +#ifdef __cplusplus +} +#endif + +#endif /*_TD_PLANN_NODES_H_*/ diff --git a/include/libs/nodes/querynodes.h b/include/libs/nodes/querynodes.h index 6046770ed1..024967289a 100644 --- a/include/libs/nodes/querynodes.h +++ b/include/libs/nodes/querynodes.h @@ -62,8 +62,10 @@ typedef struct SColumnNode { typedef struct SColumnRefNode { ENodeType type; - int32_t tupleId; - int32_t slotId; + SDataType dataType; + int16_t tupleId; + int16_t slotId; + int16_t columnId; } SColumnRefNode; typedef struct SValueNode { @@ -106,6 +108,12 @@ typedef enum EOperatorType { OP_TYPE_NMATCH, OP_TYPE_IS_NULL, OP_TYPE_IS_NOT_NULL, + OP_TYPE_IS_TRUE, + OP_TYPE_IS_FALSE, + OP_TYPE_IS_UNKNOWN, + OP_TYPE_IS_NOT_TRUE, + OP_TYPE_IS_NOT_FALSE, + OP_TYPE_IS_NOT_UNKNOWN, // json operator OP_TYPE_JSON_GET_VALUE, @@ -285,7 +293,7 @@ typedef enum ESqlClause { void nodesWalkSelectStmt(SSelectStmt* pSelect, ESqlClause clause, FNodeWalker walker, void* pContext); void nodesRewriteSelectStmt(SSelectStmt* pSelect, ESqlClause clause, FNodeRewriter rewriter, void* pContext); -int32_t nodesCollectColumns(SSelectStmt* pSelect, ESqlClause clause, uint64_t tableId, bool realCol, SNodeList** pCols); +int32_t nodesCollectColumns(SSelectStmt* pSelect, ESqlClause clause, const char* pTableAlias, SNodeList** pCols); typedef bool (*FFuncClassifier)(int32_t funcId); int32_t nodesCollectFuncs(SSelectStmt* pSelect, FFuncClassifier classifier, SNodeList** pFuncs); diff --git a/include/libs/parser/newParser.h b/include/libs/parser/newParser.h new file mode 100644 index 0000000000..fd631087db --- /dev/null +++ b/include/libs/parser/newParser.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef _TD_NEW_PARSER_H_ +#define _TD_NEW_PARSER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "parser.h" + +typedef enum EStmtType { + STMT_TYPE_CMD = 1, + STMT_TYPE_QUERY +} EStmtType; + +typedef struct SQuery { + EStmtType stmtType; + SNode* pRoot; + int32_t numOfResCols; + SSchema* pResSchema; +} SQuery; + +int32_t parser(SParseContext* pParseCxt, SQuery* pQuery); + +#ifdef __cplusplus +} +#endif + +#endif /*_TD_NEW_PARSER_H_*/ diff --git a/include/util/tjson.h b/include/util/tjson.h new file mode 100644 index 0000000000..a4eb6e5385 --- /dev/null +++ b/include/util/tjson.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef _TD_UTIL_JSON_H_ +#define _TD_UTIL_JSON_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "os.h" + +typedef void SJson; + +SJson* tjsonCreateObject(); +void tjsonDelete(SJson* pJson); + +SJson* tjsonAddArrayToObject(SJson* pJson, const char* pName); + +int32_t tjsonAddIntegerToObject(SJson* pJson, const char* pName, const uint64_t number); +int32_t tjsonAddStringToObject(SJson* pJson, const char* pName, const char* pVal); +int32_t tjsonAddItemToObject(SJson* pJson, const char* pName, SJson* pItem); +int32_t tjsonAddItemToArray(SJson* pJson, SJson* pItem); + +typedef int32_t (*FToJson)(const void* pObj, SJson* pJson); + +int32_t tjsonAddObject(SJson* pJson, const char* pName, FToJson func, const void* pObj); +int32_t tjsonAddItem(SJson* pJson, FToJson func, const void* pObj); + +typedef int32_t (*FFromJson)(const SJson* pJson, void* pObj); + +char* tjsonToString(const SJson* pJson); + +#ifdef __cplusplus +} +#endif + +#endif /*_TD_UTIL_JSON_H_*/ diff --git a/source/libs/nodes/CMakeLists.txt b/source/libs/nodes/CMakeLists.txt index 9a826e034c..e20cdc39ba 100644 --- a/source/libs/nodes/CMakeLists.txt +++ b/source/libs/nodes/CMakeLists.txt @@ -7,7 +7,7 @@ target_include_directories( ) target_link_libraries( nodes - PRIVATE os util + PRIVATE os util common qcom ) if(${BUILD_TEST}) diff --git a/source/libs/nodes/src/nodesCodeFuncs.c b/source/libs/nodes/src/nodesCodeFuncs.c index ad83bdbd19..d1f32ae314 100644 --- a/source/libs/nodes/src/nodesCodeFuncs.c +++ b/source/libs/nodes/src/nodesCodeFuncs.c @@ -13,10 +13,179 @@ * along with this program. If not, see . */ -#include "nodes.h" +#include "plannodes.h" +#include "querynodes.h" +#include "query.h" +#include "taoserror.h" +#include "tjson.h" -int32_t nodesNodeToString(const SNode* pNode, char** pStr, int32_t* pLen) { - switch (nodeType(pNode)) { +static int32_t nodeToJson(const void* pObj, SJson* pJson); + +static char* nodeName(ENodeType type) { + switch (type) { + case QUERY_NODE_COLUMN: + return "Column"; + case QUERY_NODE_VALUE: + case QUERY_NODE_OPERATOR: + case QUERY_NODE_LOGIC_CONDITION: + case QUERY_NODE_FUNCTION: + case QUERY_NODE_REAL_TABLE: + case QUERY_NODE_TEMP_TABLE: + case QUERY_NODE_JOIN_TABLE: + case QUERY_NODE_GROUPING_SET: + case QUERY_NODE_ORDER_BY_EXPR: + case QUERY_NODE_LIMIT: + case QUERY_NODE_STATE_WINDOW: + case QUERY_NODE_SESSION_WINDOW: + case QUERY_NODE_INTERVAL_WINDOW: + case QUERY_NODE_NODE_LIST: + case QUERY_NODE_FILL: + case QUERY_NODE_COLUMN_REF: + case QUERY_NODE_TARGET: + case QUERY_NODE_RAW_EXPR: + case QUERY_NODE_SET_OPERATOR: + case QUERY_NODE_SELECT_STMT: + case QUERY_NODE_SHOW_STMT: + break; + case QUERY_NODE_LOGIC_PLAN_SCAN: + return "LogicScan"; + case QUERY_NODE_LOGIC_PLAN_JOIN: + return "LogicJoin"; + case QUERY_NODE_LOGIC_PLAN_FILTER: + return "LogicFilter"; + case QUERY_NODE_LOGIC_PLAN_AGG: + return "LogicAgg"; + case QUERY_NODE_LOGIC_PLAN_PROJECT: + return "LogicProject"; + default: + break; + } + return "Unknown"; +} + +static int32_t addNodeList(SJson* pJson, const char* pName, FToJson func, const SNodeList* pList) { + if (LIST_LENGTH(pList) > 0) { + SJson* jList = tjsonAddArrayToObject(pJson, pName); + if (NULL == jList) { + return TSDB_CODE_OUT_OF_MEMORY; + } + SNode* pNode; + FOREACH(pNode, pList) { + int32_t code = tjsonAddItem(jList, func, pNode); + if (TSDB_CODE_SUCCESS != code) { + return code; + } + } + } + return TSDB_CODE_SUCCESS; +} + +static const char* jkTableMetaUid = "TableMetaUid"; +static const char* jkTableMetaSuid = "TableMetaSuid"; + +static int32_t tableMetaToJson(const void* pObj, SJson* pJson) { + const STableMeta* pNode = (const STableMeta*)pObj; + + int32_t code = tjsonAddIntegerToObject(pJson, jkTableMetaUid, pNode->uid); + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddIntegerToObject(pJson, jkTableMetaSuid, pNode->suid); + } + + return code; +} + +static const char* jkLogicPlanId = "Id"; +static const char* jkLogicPlanTargets = "Targets"; +static const char* jkLogicPlanConditions = "Conditions"; +static const char* jkLogicPlanChildren = "Children"; + +static int32_t logicPlanNodeToJson(const void* pObj, SJson* pJson) { + const SLogicNode* pNode = (const SLogicNode*)pObj; + + int32_t code = tjsonAddIntegerToObject(pJson, jkLogicPlanId, pNode->id); + if (TSDB_CODE_SUCCESS == code) { + code = addNodeList(pJson, jkLogicPlanTargets, nodeToJson, pNode->pTargets); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddObject(pJson, jkLogicPlanConditions, nodeToJson, pNode->pConditions); + } + if (TSDB_CODE_SUCCESS == code) { + code = addNodeList(pJson, jkLogicPlanChildren, nodeToJson, pNode->pChildren); + } + + return code; +} + +static const char* jkScanLogicPlanScanCols = "ScanCols"; +static const char* jkScanLogicPlanTableMeta = "TableMeta"; + +static int32_t logicScanToJson(const void* pObj, SJson* pJson) { + const SScanLogicNode* pNode = (const SScanLogicNode*)pObj; + + int32_t code = logicPlanNodeToJson(pObj, pJson); + if (TSDB_CODE_SUCCESS == code) { + code = addNodeList(pJson, jkScanLogicPlanScanCols, nodeToJson, pNode->pScanCols); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddObject(pJson, jkScanLogicPlanTableMeta, tableMetaToJson, pNode->pMeta); + } + + return code; +} + +static const char* jkProjectLogicPlanProjections = "Projections"; + +static int32_t logicProjectToJson(const void* pObj, SJson* pJson) { + const SProjectLogicNode* pNode = (const SProjectLogicNode*)pObj; + + int32_t code = logicPlanNodeToJson(pObj, pJson); + if (TSDB_CODE_SUCCESS == code) { + code = addNodeList(pJson, jkProjectLogicPlanProjections, nodeToJson, pNode->pProjections); + } + + return code; +} + +static const char* jkJoinLogicPlanJoinType = "JoinType"; +static const char* jkJoinLogicPlanOnConditions = "OnConditions"; + +static int32_t logicJoinToJson(const void* pObj, SJson* pJson) { + const SJoinLogicNode* pNode = (const SJoinLogicNode*)pObj; + + int32_t code = logicPlanNodeToJson(pObj, pJson); + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddIntegerToObject(pJson, jkJoinLogicPlanJoinType, pNode->joinType); + } + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddObject(pJson, jkJoinLogicPlanOnConditions, nodeToJson, pNode->pOnConditions); + } + + return code; +} + +static int32_t logicFilterToJson(const void* pObj, SJson* pJson) { + return logicPlanNodeToJson(pObj, pJson); +} + +static const char* jkAggLogicPlanGroupKeys = "GroupKeys"; +static const char* jkAggLogicPlanAggFuncs = "AggFuncs"; + +static int32_t logicAggToJson(const void* pObj, SJson* pJson) { + const SAggLogicNode* pNode = (const SAggLogicNode*)pObj; + + int32_t code = logicPlanNodeToJson(pObj, pJson); + if (TSDB_CODE_SUCCESS == code) { + code = addNodeList(pJson, jkAggLogicPlanGroupKeys, nodeToJson, pNode->pGroupKeys); + } + if (TSDB_CODE_SUCCESS == code) { + code = addNodeList(pJson, jkAggLogicPlanAggFuncs, nodeToJson, pNode->pAggFuncs); + } + + return code; +} + +static int32_t specificNodeToJson(const void* pObj, SJson* pJson) { + switch (nodeType(pObj)) { case QUERY_NODE_COLUMN: case QUERY_NODE_VALUE: case QUERY_NODE_OPERATOR: @@ -31,14 +200,68 @@ int32_t nodesNodeToString(const SNode* pNode, char** pStr, int32_t* pLen) { case QUERY_NODE_STATE_WINDOW: case QUERY_NODE_SESSION_WINDOW: case QUERY_NODE_INTERVAL_WINDOW: + case QUERY_NODE_NODE_LIST: + case QUERY_NODE_FILL: + case QUERY_NODE_COLUMN_REF: + case QUERY_NODE_TARGET: + case QUERY_NODE_RAW_EXPR: case QUERY_NODE_SET_OPERATOR: case QUERY_NODE_SELECT_STMT: case QUERY_NODE_SHOW_STMT: + break; + case QUERY_NODE_LOGIC_PLAN_SCAN: + return logicScanToJson(pObj, pJson); + case QUERY_NODE_LOGIC_PLAN_JOIN: + return logicJoinToJson(pObj, pJson); + case QUERY_NODE_LOGIC_PLAN_FILTER: + return logicFilterToJson(pObj, pJson); + case QUERY_NODE_LOGIC_PLAN_AGG: + return logicAggToJson(pObj, pJson); + case QUERY_NODE_LOGIC_PLAN_PROJECT: + return logicProjectToJson(pObj, pJson); default: break; } + return TSDB_CODE_SUCCESS; +} + +static const char* jkNodeType = "Type"; +static int32_t nodeToJson(const void* pObj, SJson* pJson) { + const SNode* pNode = (const SNode*)pObj; + + char* pNodeName = nodeName(nodeType(pNode)); + int32_t code = tjsonAddStringToObject(pJson, jkNodeType, pNodeName); + if (TSDB_CODE_SUCCESS == code) { + code = tjsonAddObject(pJson, pNodeName, specificNodeToJson, pNode); + } + + return code; +} + +int32_t nodesNodeToString(const SNode* pNode, char** pStr, int32_t* pLen) { + if (NULL == pNode || NULL == pStr || NULL == pLen) { + return TSDB_CODE_SUCCESS; + } + + SJson* pJson = tjsonCreateObject(); + if (NULL == pJson) { + terrno = TSDB_CODE_OUT_OF_MEMORY; + return TSDB_CODE_OUT_OF_MEMORY; + } + + int32_t code = nodeToJson(pNode, pJson); + if (TSDB_CODE_SUCCESS != code) { + terrno = code; + return code; + } + + *pStr = tjsonToString(pJson); + tjsonDelete(pJson); + + *pLen = strlen(*pStr) + 1; + return TSDB_CODE_SUCCESS; } int32_t nodesStringToNode(const char* pStr, SNode** pNode) { - + return TSDB_CODE_SUCCESS; } diff --git a/source/libs/nodes/src/nodesUtilFuncs.c b/source/libs/nodes/src/nodesUtilFuncs.c index 50ddd14bf5..868af93c92 100644 --- a/source/libs/nodes/src/nodesUtilFuncs.c +++ b/source/libs/nodes/src/nodesUtilFuncs.c @@ -14,7 +14,7 @@ */ #include "querynodes.h" -#include "nodesShowStmts.h" +#include "plannodes.h" #include "taos.h" #include "taoserror.h" #include "thash.h" @@ -68,8 +68,18 @@ SNode* nodesMakeNode(ENodeType type) { return makeNode(type, sizeof(SSetOperator)); case QUERY_NODE_SELECT_STMT: return makeNode(type, sizeof(SSelectStmt)); - case QUERY_NODE_SHOW_STMT: - return makeNode(type, sizeof(SShowStmt)); + // case QUERY_NODE_SHOW_STMT: + // return makeNode(type, sizeof(SShowStmt)); + case QUERY_NODE_LOGIC_PLAN_SCAN: + return makeNode(type, sizeof(SScanLogicNode)); + case QUERY_NODE_LOGIC_PLAN_JOIN: + return makeNode(type, sizeof(SJoinLogicNode)); + case QUERY_NODE_LOGIC_PLAN_FILTER: + return makeNode(type, sizeof(SFilterLogicNode)); + case QUERY_NODE_LOGIC_PLAN_AGG: + return makeNode(type, sizeof(SAggLogicNode)); + case QUERY_NODE_LOGIC_PLAN_PROJECT: + return makeNode(type, sizeof(SProjectLogicNode)); default: break; } @@ -121,6 +131,15 @@ int32_t nodesListAppend(SNodeList* pList, SNode* pNode) { return TSDB_CODE_SUCCESS; } +int32_t nodesListAppendList(SNodeList* pTarget, SNodeList* pSrc) { + pTarget->pTail->pNext = pSrc->pHead; + pSrc->pHead->pPrev = pTarget->pTail; + pTarget->pTail = pSrc->pTail; + pTarget->length += pSrc->length; + tfree(pSrc); + return TSDB_CODE_SUCCESS; +} + SListCell* nodesListErase(SNodeList* pList, SListCell* pCell) { if (NULL == pCell->pPrev) { pList->pHead = pCell->pNext; @@ -129,6 +148,7 @@ SListCell* nodesListErase(SNodeList* pList, SListCell* pCell) { pCell->pNext->pPrev = pCell->pPrev; } SListCell* pNext = pCell->pNext; + nodesDestroyNode(pCell->pNode); tfree(pCell); --(pList->length); return pNext; @@ -185,6 +205,14 @@ bool nodesIsComparisonOp(const SOperatorNode* pOp) { case OP_TYPE_NOT_LIKE: case OP_TYPE_MATCH: case OP_TYPE_NMATCH: + case OP_TYPE_IS_NULL: + case OP_TYPE_IS_NOT_NULL: + case OP_TYPE_IS_TRUE: + case OP_TYPE_IS_FALSE: + case OP_TYPE_IS_UNKNOWN: + case OP_TYPE_IS_NOT_TRUE: + case OP_TYPE_IS_NOT_FALSE: + case OP_TYPE_IS_NOT_UNKNOWN: return true; default: break; @@ -213,8 +241,7 @@ bool nodesIsTimelineQuery(const SNode* pQuery) { typedef struct SCollectColumnsCxt { int32_t errCode; - uint64_t tableId; - bool realCol; + const char* pTableAlias; SNodeList* pCols; SHashObj* pColIdHash; } SCollectColumnsCxt; @@ -232,27 +259,24 @@ static EDealRes doCollect(SCollectColumnsCxt* pCxt, int32_t id, SNode* pNode) { static EDealRes collectColumns(SNode* pNode, void* pContext) { SCollectColumnsCxt* pCxt = (SCollectColumnsCxt*)pContext; - - if (pCxt->realCol && QUERY_NODE_COLUMN == nodeType(pNode)) { + if (QUERY_NODE_COLUMN == nodeType(pNode)) { SColumnNode* pCol = (SColumnNode*)pNode; int32_t colId = pCol->colId; - if (pCxt->tableId == pCol->tableId && colId > 0) { + if (0 == strcmp(pCxt->pTableAlias, pCol->tableAlias)) { return doCollect(pCxt, colId, pNode); } - } else if (!pCxt->realCol && QUERY_NODE_COLUMN_REF == nodeType(pNode)) { - return doCollect(pCxt, ((SColumnRefNode*)pNode)->slotId, pNode); } return DEAL_RES_CONTINUE; } -int32_t nodesCollectColumns(SSelectStmt* pSelect, ESqlClause clause, uint64_t tableId, bool realCol, SNodeList** pCols) { +int32_t nodesCollectColumns(SSelectStmt* pSelect, ESqlClause clause, const char* pTableAlias, SNodeList** pCols) { if (NULL == pSelect || NULL == pCols) { return TSDB_CODE_SUCCESS; } SCollectColumnsCxt cxt = { .errCode = TSDB_CODE_SUCCESS, - .realCol = realCol, + .pTableAlias = pTableAlias, .pCols = nodesMakeList(), .pColIdHash = taosHashInit(128, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), true, HASH_NO_LOCK) }; @@ -303,6 +327,12 @@ int32_t nodesCollectFuncs(SSelectStmt* pSelect, FFuncClassifier classifier, SNod nodesDestroyList(cxt.pFuncs); return cxt.errCode; } - *pFuncs = cxt.pFuncs; + if (LIST_LENGTH(cxt.pFuncs) > 0) { + *pFuncs = cxt.pFuncs; + } else { + nodesDestroyList(cxt.pFuncs); + *pFuncs = NULL; + } + return TSDB_CODE_SUCCESS; } diff --git a/source/libs/parser/inc/parserImpl.h b/source/libs/parser/inc/parserImpl.h index 4f6f0cf387..f2777a2368 100644 --- a/source/libs/parser/inc/parserImpl.h +++ b/source/libs/parser/inc/parserImpl.h @@ -13,27 +13,15 @@ * along with this program. If not, see . */ -#ifndef _TD_AST_CREATE_FUNCS_H_ -#define _TD_AST_CREATE_FUNCS_H_ +#ifndef _TD_PARSER_IMPL_H_ +#define _TD_PARSER_IMPL_H_ #ifdef __cplusplus extern "C" { #endif #include "querynodes.h" -#include "parser.h" - -typedef enum EStmtType { - STMT_TYPE_CMD = 1, - STMT_TYPE_QUERY -} EStmtType; - -typedef struct SQuery { - EStmtType stmtType; - SNode* pRoot; - int32_t numOfResCols; - SSchema* pResSchema; -} SQuery; +#include "newParser.h" int32_t doParse(SParseContext* pParseCxt, SQuery* pQuery); int32_t doTranslate(SParseContext* pParseCxt, SQuery* pQuery); @@ -42,4 +30,4 @@ int32_t doTranslate(SParseContext* pParseCxt, SQuery* pQuery); } #endif -#endif /*_TD_AST_CREATE_FUNCS_H_*/ +#endif /*_TD_PARSER_IMPL_H_*/ diff --git a/source/libs/parser/src/parserImpl.c b/source/libs/parser/src/parserImpl.c index 6f80412bfc..d353c245cb 100644 --- a/source/libs/parser/src/parserImpl.c +++ b/source/libs/parser/src/parserImpl.c @@ -880,7 +880,6 @@ static int32_t translateOrderByPosition(STranslateContext* pCxt, SNodeList* pPro int32_t pos = getPositionValue(pVal); if (pos < 0) { ERASE_NODE(pOrderByList); - nodesDestroyNode(pNode); continue; } else if (0 == pos || pos > LIST_LENGTH(pProjectionList)) { return generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_WRONG_NUMBER_OF_SELECT); @@ -1058,3 +1057,11 @@ int32_t doTranslate(SParseContext* pParseCxt, SQuery* pQuery) { } return code; } + +int32_t parser(SParseContext* pParseCxt, SQuery* pQuery) { + int32_t code = doParse(pParseCxt, pQuery); + if (TSDB_CODE_SUCCESS == code) { + code = doTranslate(pParseCxt, pQuery); + } + return code; +} diff --git a/source/libs/planner/inc/plannerImpl.h b/source/libs/planner/inc/plannerImpl.h index 1960eb52fb..d89cc26700 100644 --- a/source/libs/planner/inc/plannerImpl.h +++ b/source/libs/planner/inc/plannerImpl.h @@ -20,43 +20,10 @@ extern "C" { #endif -#include "querynodes.h" +#include "plannodes.h" #include "planner.h" -typedef struct SLogicNode { - ENodeType type; - int32_t id; - SNodeList* pTargets; - SNode* pConditions; - SNodeList* pChildren; - struct SLogicNode* pParent; -} SLogicNode; - -typedef struct SScanLogicNode { - SLogicNode node; - SNodeList* pScanCols; - struct STableMeta* pMeta; -} SScanLogicNode; - -typedef struct SJoinLogicNode { - SLogicNode node; - EJoinType joinType; - SNode* pOnConditions; -} SJoinLogicNode; - -typedef struct SFilterLogicNode { - SLogicNode node; -} SFilterLogicNode; - -typedef struct SAggLogicNode { - SLogicNode node; - SNodeList* pGroupKeys; - SNodeList* pAggFuncs; -} SAggLogicNode; - -typedef struct SProjectLogicNode { - SLogicNode node; -} SProjectLogicNode; +int32_t createLogicPlan(SNode* pNode, SLogicNode** pLogicNode); #ifdef __cplusplus } diff --git a/source/libs/planner/src/plannerImpl.c b/source/libs/planner/src/plannerImpl.c index 11f721bda5..40a82f4175 100644 --- a/source/libs/planner/src/plannerImpl.c +++ b/source/libs/planner/src/plannerImpl.c @@ -19,6 +19,7 @@ #define CHECK_ALLOC(p, res) \ do { \ if (NULL == p) { \ + printf("%s : %d\n", __FUNCTION__, __LINE__); \ pCxt->errCode = TSDB_CODE_OUT_OF_MEMORY; \ return res; \ } \ @@ -28,6 +29,7 @@ do { \ int32_t code = exec; \ if (TSDB_CODE_SUCCESS != code) { \ + printf("%s : %d\n", __FUNCTION__, __LINE__); \ pCxt->errCode = code; \ return res; \ } \ @@ -44,8 +46,7 @@ static SLogicNode* createLogicNodeByTable(SPlanContext* pCxt, SSelectStmt* pSele typedef struct SRewriteExprCxt { int32_t errCode; - int32_t planNodeId; - SNodeList* pTargets; + SNodeList* pExprs; } SRewriteExprCxt; static EDealRes doRewriteExpr(SNode** pNode, void* pContext) { @@ -53,34 +54,44 @@ static EDealRes doRewriteExpr(SNode** pNode, void* pContext) { case QUERY_NODE_OPERATOR: case QUERY_NODE_LOGIC_CONDITION: case QUERY_NODE_FUNCTION: { + SRewriteExprCxt* pCxt = (SRewriteExprCxt*)pContext; + SNode* pExpr; + int32_t index = 0; + FOREACH(pExpr, pCxt->pExprs) { + if (nodesEqualNode(pExpr, *pNode)) { + SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN); + if (NULL == pCol) { + pCxt->errCode = TSDB_CODE_OUT_OF_MEMORY; + return DEAL_RES_ERROR; + } + SExprNode* pToBeRewrittenExpr = (SExprNode*)(*pNode); + pCol->node.resType = pToBeRewrittenExpr->resType; + strcpy(pCol->node.aliasName, pToBeRewrittenExpr->aliasName); + strcpy(pCol->colName, ((SExprNode*)pExpr)->aliasName); + nodesDestroyNode(*pNode); + *pNode = (SNode*)pCol; + return DEAL_RES_IGNORE_CHILD; + } + ++index; + } break; } default: break; } - SRewriteExprCxt* pCxt = (SRewriteExprCxt*)pContext; - SNode* pTarget; - int32_t index = 0; - FOREACH(pTarget, pCxt->pTargets) { - if (nodesEqualNode(pTarget, *pNode)) { - SColumnRefNode* pCol = (SColumnRefNode*)nodesMakeNode(QUERY_NODE_COLUMN_REF); - if (NULL == pCol) { - pCxt->errCode = TSDB_CODE_OUT_OF_MEMORY; - return DEAL_RES_ERROR; - } - pCol->tupleId = pCxt->planNodeId; - pCol->slotId = index; - nodesDestroyNode(*pNode); - *pNode = (SNode*)pCol; - return DEAL_RES_IGNORE_CHILD; - } - ++index; - } + return DEAL_RES_CONTINUE; } -static int32_t rewriteExpr(int32_t planNodeId, SNodeList* pTargets, SSelectStmt* pSelect, ESqlClause clause) { - SRewriteExprCxt cxt = { .errCode = TSDB_CODE_SUCCESS, .planNodeId = planNodeId, .pTargets = pTargets }; +static int32_t rewriteExpr(int32_t planNodeId, int32_t rewriteId, SNodeList* pExprs, SSelectStmt* pSelect, ESqlClause clause) { + SNode* pNode; + FOREACH(pNode, pExprs) { + if (QUERY_NODE_COLUMN == nodeType(pNode) || QUERY_NODE_VALUE == nodeType(pNode)) { + continue; + } + sprintf(((SExprNode*)pNode)->aliasName, "#expr_%d_%d", planNodeId, rewriteId); + } + SRewriteExprCxt cxt = { .errCode = TSDB_CODE_SUCCESS, .pExprs = pExprs }; nodesRewriteSelectStmt(pSelect, clause, doRewriteExpr, &cxt); return cxt.errCode; } @@ -114,23 +125,6 @@ error: return pRoot; } -static SNodeList* createScanTargets(int32_t planNodeId, int32_t numOfScanCols) { - SNodeList* pTargets = nodesMakeList(); - if (NULL == pTargets) { - return NULL; - } - for (int32_t i = 0; i < numOfScanCols; ++i) { - SColumnRefNode* pCol = (SColumnRefNode*)nodesMakeNode(QUERY_NODE_COLUMN_REF); - if (NULL == pCol || TSDB_CODE_SUCCESS != nodesListAppend(pTargets, (SNode*)pCol)) { - nodesDestroyList(pTargets); - return NULL; - } - pCol->tupleId = planNodeId; - pCol->slotId = i; - } - return pTargets; -} - static SLogicNode* createScanLogicNode(SPlanContext* pCxt, SSelectStmt* pSelect, SRealTableNode* pRealTable) { SScanLogicNode* pScan = (SScanLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_SCAN); CHECK_ALLOC(pScan, NULL); @@ -140,22 +134,25 @@ static SLogicNode* createScanLogicNode(SPlanContext* pCxt, SSelectStmt* pSelect, // set columns to scan SNodeList* pCols = NULL; - CHECK_CODE(nodesCollectColumns(pSelect, SQL_CLAUSE_FROM, pScan->pMeta->uid, true, &pCols), (SLogicNode*)pScan); + CHECK_CODE(nodesCollectColumns(pSelect, SQL_CLAUSE_FROM, pRealTable->table.tableAlias, &pCols), (SLogicNode*)pScan); pScan->pScanCols = nodesCloneList(pCols); CHECK_ALLOC(pScan->pScanCols, (SLogicNode*)pScan); - // pScanCols of SScanLogicNode is equivalent to pTargets of other logic nodes - CHECK_CODE(rewriteExpr(pScan->node.id, pScan->pScanCols, pSelect, SQL_CLAUSE_FROM), (SLogicNode*)pScan); - // set output - pScan->node.pTargets = createScanTargets(pScan->node.id, LIST_LENGTH(pScan->pScanCols)); + pScan->node.pTargets = nodesCloneList(pCols); CHECK_ALLOC(pScan->node.pTargets, (SLogicNode*)pScan); return (SLogicNode*)pScan; } static SLogicNode* createSubqueryLogicNode(SPlanContext* pCxt, SSelectStmt* pSelect, STempTableNode* pTable) { - return createQueryLogicNode(pCxt, pTable->pSubquery); + SLogicNode* pRoot = createQueryLogicNode(pCxt, pTable->pSubquery); + CHECK_ALLOC(pRoot, NULL); + SNode* pNode; + FOREACH(pNode, pRoot->pTargets) { + strcpy(((SColumnNode*)pNode)->tableAlias, pTable->table.tableAlias); + } + return pRoot; } static SLogicNode* createJoinLogicNode(SPlanContext* pCxt, SSelectStmt* pSelect, SJoinTableNode* pJoinTable) { @@ -179,12 +176,12 @@ static SLogicNode* createJoinLogicNode(SPlanContext* pCxt, SSelectStmt* pSelect, pJoin->pOnConditions = nodesCloneNode(pJoinTable->pOnCond); CHECK_ALLOC(pJoin->pOnConditions, (SLogicNode*)pJoin); - // set the output and rewrite the expression in subsequent clauses with the output - SNodeList* pCols = NULL; - CHECK_CODE(nodesCollectColumns(pSelect, SQL_CLAUSE_FROM, 0, false, &pCols), (SLogicNode*)pJoin); - pJoin->node.pTargets = nodesCloneList(pCols); + // set the output + pJoin->node.pTargets = nodesCloneList(pLeft->pTargets); CHECK_ALLOC(pJoin->node.pTargets, (SLogicNode*)pJoin); - CHECK_CODE(rewriteExpr(pJoin->node.id, pJoin->node.pTargets, pSelect, SQL_CLAUSE_FROM), (SLogicNode*)pJoin); + SNodeList* pTargets = nodesCloneList(pRight->pTargets); + CHECK_ALLOC(pTargets, (SLogicNode*)pJoin); + nodesListAppendList(pJoin->node.pTargets, pTargets); return (SLogicNode*)pJoin; } @@ -203,7 +200,7 @@ static SLogicNode* createLogicNodeByTable(SPlanContext* pCxt, SSelectStmt* pSele return NULL; } -static SLogicNode* createWhereFilterLogicNode(SPlanContext* pCxt, SSelectStmt* pSelect) { +static SLogicNode* createWhereFilterLogicNode(SPlanContext* pCxt, SLogicNode* pChild, SSelectStmt* pSelect) { if (NULL == pSelect->pWhere) { return NULL; } @@ -216,16 +213,44 @@ static SLogicNode* createWhereFilterLogicNode(SPlanContext* pCxt, SSelectStmt* p pFilter->node.pConditions = nodesCloneNode(pSelect->pWhere); CHECK_ALLOC(pFilter->node.pConditions, (SLogicNode*)pFilter); - // set the output and rewrite the expression in subsequent clauses with the output - SNodeList* pCols = NULL; - CHECK_CODE(nodesCollectColumns(pSelect, SQL_CLAUSE_WHERE, 0, false, &pCols), (SLogicNode*)pFilter); - pFilter->node.pTargets = nodesCloneList(pCols); + // set the output + pFilter->node.pTargets = nodesCloneList(pChild->pTargets); CHECK_ALLOC(pFilter->node.pTargets, (SLogicNode*)pFilter); - CHECK_CODE(rewriteExpr(pFilter->node.id, pFilter->node.pTargets, pSelect, SQL_CLAUSE_WHERE), (SLogicNode*)pFilter); return (SLogicNode*)pFilter; } +static SNodeList* createColumnByRewriteExps(SPlanContext* pCxt, SNodeList* pExprs) { + SNodeList* pList = nodesMakeList(); + CHECK_ALLOC(pList, NULL); + SNode* pNode; + FOREACH(pNode, pExprs) { + if (QUERY_NODE_VALUE == nodeType(pNode)) { + continue; + } else if (QUERY_NODE_COLUMN == nodeType(pNode)) { + SNode* pCol = nodesCloneNode(pNode); + if (NULL == pCol) { + goto error; + } + if (TSDB_CODE_SUCCESS != nodesListAppend(pList, pCol)) { + goto error; + } + } else { + SExprNode* pExpr = (SExprNode*)pNode; + SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN); + if (NULL == pCol) { + goto error; + } + pCol->node.resType = pExpr->resType; + strcpy(pCol->colName, pExpr->aliasName); + } + } + return pList; +error: + nodesDestroyList(pList); + return NULL; +} + static SLogicNode* createAggLogicNode(SPlanContext* pCxt, SSelectStmt* pSelect) { SNodeList* pAggFuncs = NULL; CHECK_CODE(nodesCollectFuncs(pSelect, fmIsAggFunc, &pAggFuncs), NULL); @@ -242,25 +267,54 @@ static SLogicNode* createAggLogicNode(SPlanContext* pCxt, SSelectStmt* pSelect) CHECK_ALLOC(pAgg->pGroupKeys, (SLogicNode*)pAgg); pAgg->pAggFuncs = nodesCloneList(pAggFuncs); CHECK_ALLOC(pAgg->pAggFuncs, (SLogicNode*)pAgg); + + // rewrite the expression in subsequent clauses + CHECK_CODE(rewriteExpr(pAgg->node.id, 1, pAgg->pGroupKeys, pSelect, SQL_CLAUSE_GROUP_BY), (SLogicNode*)pAgg); + CHECK_CODE(rewriteExpr(pAgg->node.id, 1 + LIST_LENGTH(pAgg->pGroupKeys), pAgg->pAggFuncs, pSelect, SQL_CLAUSE_GROUP_BY), (SLogicNode*)pAgg); + pAgg->node.pConditions = nodesCloneNode(pSelect->pHaving); CHECK_ALLOC(pAgg->node.pConditions, (SLogicNode*)pAgg); - // set the output and rewrite the expression in subsequent clauses with the output - SNodeList* pCols = NULL; - CHECK_CODE(nodesCollectColumns(pSelect, SQL_CLAUSE_HAVING, 0, false, &pCols), (SLogicNode*)pAgg); - pAgg->node.pTargets = nodesCloneList(pCols); + // set the output + pAgg->node.pTargets = createColumnByRewriteExps(pCxt, pAgg->pGroupKeys); CHECK_ALLOC(pAgg->node.pTargets, (SLogicNode*)pAgg); - CHECK_CODE(rewriteExpr(pAgg->node.id, pAgg->node.pTargets, pSelect, SQL_CLAUSE_HAVING), (SLogicNode*)pAgg); - + SNodeList* pTargets = createColumnByRewriteExps(pCxt, pAgg->pAggFuncs); + CHECK_ALLOC(pTargets, (SLogicNode*)pAgg); + nodesListAppendList(pAgg->node.pTargets, pTargets); + return (SLogicNode*)pAgg; } +static SNodeList* createColumnByProjections(SPlanContext* pCxt, SNodeList* pExprs) { + SNodeList* pList = nodesMakeList(); + CHECK_ALLOC(pList, NULL); + SNode* pNode; + FOREACH(pNode, pExprs) { + SExprNode* pExpr = (SExprNode*)pNode; + SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN); + if (NULL == pCol) { + goto error; + } + pCol->node.resType = pExpr->resType; + strcpy(pCol->colName, pExpr->aliasName); + if (TSDB_CODE_SUCCESS != nodesListAppend(pList, (SNode*)pCol)) { + goto error; + } + } + return pList; +error: + nodesDestroyList(pList); + return NULL; +} + static SLogicNode* createProjectLogicNode(SPlanContext* pCxt, SSelectStmt* pSelect) { SProjectLogicNode* pProject = (SProjectLogicNode*)nodesMakeNode(QUERY_NODE_LOGIC_PLAN_PROJECT); CHECK_ALLOC(pProject, NULL); pProject->node.id = pCxt->planNodeId++; - pProject->node.pTargets = nodesCloneList(pSelect->pProjectionList); + pProject->pProjections = nodesCloneList(pSelect->pProjectionList); + + pProject->node.pTargets = createColumnByProjections(pCxt,pSelect->pProjectionList); CHECK_ALLOC(pProject->node.pTargets, (SLogicNode*)pProject); return (SLogicNode*)pProject; @@ -269,7 +323,7 @@ static SLogicNode* createProjectLogicNode(SPlanContext* pCxt, SSelectStmt* pSele static SLogicNode* createSelectLogicNode(SPlanContext* pCxt, SSelectStmt* pSelect) { SLogicNode* pRoot = createLogicNodeByTable(pCxt, pSelect, pSelect->pFromTable); if (TSDB_CODE_SUCCESS == pCxt->errCode) { - pRoot = pushLogicNode(pCxt, pRoot, createWhereFilterLogicNode(pCxt, pSelect)); + pRoot = pushLogicNode(pCxt, pRoot, createWhereFilterLogicNode(pCxt, pRoot, pSelect)); } if (TSDB_CODE_SUCCESS == pCxt->errCode) { pRoot = pushLogicNode(pCxt, pRoot, createAggLogicNode(pCxt, pSelect)); diff --git a/source/libs/planner/test/CMakeLists.txt b/source/libs/planner/test/CMakeLists.txt index 7fbfcfe7ef..cd60b503b9 100644 --- a/source/libs/planner/test/CMakeLists.txt +++ b/source/libs/planner/test/CMakeLists.txt @@ -13,7 +13,7 @@ ADD_EXECUTABLE(plannerTest TARGET_LINK_LIBRARIES( plannerTest - PUBLIC os util common planner parser catalog transport gtest function qcom + PUBLIC os util common nodes planner parser catalog transport gtest function qcom ) TARGET_INCLUDE_DIRECTORIES( diff --git a/source/libs/planner/test/newPlannerTest.cpp b/source/libs/planner/test/newPlannerTest.cpp new file mode 100644 index 0000000000..c227bf88ba --- /dev/null +++ b/source/libs/planner/test/newPlannerTest.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include + +#include + +#include "plannerImpl.h" +#include "newParser.h" + +using namespace std; +using namespace testing; + +class NewPlannerTest : 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 code = parser(&cxt_, &query_); + // cout << "parser return " << code << endl; + if (code != TSDB_CODE_SUCCESS) { + cout << "sql:[" << cxt_.pSql << "] parser code:" << tstrerror(code) << ", msg:" << errMagBuf_ << endl; + return false; + } + SLogicNode* pLogicPlan = nullptr; + code = createLogicPlan(query_.pRoot, &pLogicPlan); + if (code != TSDB_CODE_SUCCESS) { + cout << "sql:[" << cxt_.pSql << "] plan code:" << tstrerror(code) << endl; + return false; + } + char* pStr = NULL; + int32_t len = 0; + code = nodesNodeToString((const SNode*)pLogicPlan, &pStr, &len); + if (code != TSDB_CODE_SUCCESS) { + cout << "sql:[" << cxt_.pSql << "] toString code:" << tstrerror(code) << endl; + return false; + } + cout << "logic plan : " << endl; + cout << pStr << endl; + return true; + } + +private: + static const int max_err_len = 1024; + + void reset() { + memset(&cxt_, 0, sizeof(cxt_)); + memset(errMagBuf_, 0, max_err_len); + cxt_.pMsg = errMagBuf_; + cxt_.msgLen = max_err_len; + } + + string acctId_; + string db_; + char errMagBuf_[max_err_len]; + string sqlBuf_; + SParseContext cxt_; + SQuery query_; +}; + +TEST_F(NewPlannerTest, simple) { + setDatabase("root", "test"); + + bind("SELECT * FROM t1"); + ASSERT_TRUE(run()); +} diff --git a/source/util/CMakeLists.txt b/source/util/CMakeLists.txt index 760a66a4fb..7a47639e75 100644 --- a/source/util/CMakeLists.txt +++ b/source/util/CMakeLists.txt @@ -10,7 +10,7 @@ target_link_libraries( util PRIVATE os PUBLIC lz4_static - PUBLIC api + PUBLIC api cjson ) if(${BUILD_TEST}) diff --git a/source/util/src/tjson.c b/source/util/src/tjson.c new file mode 100644 index 0000000000..556e8f8060 --- /dev/null +++ b/source/util/src/tjson.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "tjson.h" + +#include "taoserror.h" +#include "cJSON.h" + +SJson* tjsonCreateObject() { + return cJSON_CreateObject(); +} + +void tjsonDelete(SJson* pJson) { + cJSON_Delete((cJSON*)pJson); +} + +int32_t tjsonAddIntegerToObject(SJson* pJson, const char* pName, const uint64_t number) { + char tmp[40] = {0}; + snprintf(tmp, tListLen(tmp), "%"PRId64, number); + return tjsonAddStringToObject(pJson, pName, tmp); +} + +int32_t tjsonAddStringToObject(SJson* pJson, const char* pName, const char* pVal) { + return (NULL == cJSON_AddStringToObject((cJSON*)pJson, pName, pVal) ? TSDB_CODE_FAILED : TSDB_CODE_SUCCESS); +} + +SJson* tjsonAddArrayToObject(SJson* pJson, const char* pName) { + return cJSON_AddArrayToObject((cJSON*)pJson, pName); +} + +int32_t tjsonAddItemToObject(SJson *pJson, const char* pName, SJson* pItem) { + return (cJSON_AddItemToObject((cJSON*)pJson, pName, pItem) ? TSDB_CODE_SUCCESS : TSDB_CODE_FAILED); +} + +int32_t tjsonAddItemToArray(SJson* pJson, SJson* pItem) { + return (cJSON_AddItemToArray((cJSON*)pJson, pItem) ? TSDB_CODE_SUCCESS : TSDB_CODE_FAILED); +} + +int32_t tjsonAddObject(SJson* pJson, const char* pName, FToJson func, const void* pObj) { + if (NULL == pObj) { + return TSDB_CODE_SUCCESS; + } + + SJson* pJobj = tjsonCreateObject(); + if (NULL == pJobj || TSDB_CODE_SUCCESS != func(pObj, pJobj)) { + printf("%s:%d code = %d\n", __FUNCTION__, __LINE__, TSDB_CODE_FAILED); + tjsonDelete(pJobj); + return TSDB_CODE_FAILED; + } + return tjsonAddItemToObject(pJson, pName, pJobj); +} + +int32_t tjsonAddItem(SJson* pJson, FToJson func, const void* pObj) { + SJson* pJobj = tjsonCreateObject(); + if (NULL == pJobj || TSDB_CODE_SUCCESS != func(pObj, pJobj)) { + tjsonDelete(pJobj); + return TSDB_CODE_FAILED; + } + return tjsonAddItemToArray(pJson, pJobj); +} + +char* tjsonToString(const SJson* pJson) { + return cJSON_Print((cJSON*)pJson); +}