Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
taosdata
TDengine
提交
cd7a0e55
T
TDengine
项目概览
taosdata
/
TDengine
大约 2 年 前同步成功
通知
1192
Star
22018
Fork
4786
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
TDengine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
cd7a0e55
编写于
2月 28, 2022
作者:
X
Xiaoyu Wang
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
TD-13747 New SQL model integration
上级
768e0593
变更
22
隐藏空白更改
内联
并排
Showing
22 changed file
with
1086 addition
and
3572 deletion
+1086
-3572
include/libs/nodes/plannodes.h
include/libs/nodes/plannodes.h
+0
-1
include/libs/parser/parser.h
include/libs/parser/parser.h
+0
-81
include/libs/planner/planner.h
include/libs/planner/planner.h
+0
-194
source/client/src/clientImpl.c
source/client/src/clientImpl.c
+6
-8
source/libs/parser/inc/astCreateFuncs.h
source/libs/parser/inc/astCreateFuncs.h
+9
-2
source/libs/parser/inc/parserInt.h
source/libs/parser/inc/parserInt.h
+3
-4
source/libs/parser/inc/parserUtil.h
source/libs/parser/inc/parserUtil.h
+3
-4
source/libs/parser/src/astCreateContext.c
source/libs/parser/src/astCreateContext.c
+0
-29
source/libs/parser/src/astParse.c
source/libs/parser/src/astParse.c
+239
-0
source/libs/parser/src/astTranslate.c
source/libs/parser/src/astTranslate.c
+1
-235
source/libs/parser/src/parser.c
source/libs/parser/src/parser.c
+10
-2
source/libs/parser/test/parserTest.cpp
source/libs/parser/test/parserTest.cpp
+1
-1
source/libs/planner/inc/plannerInt.h
source/libs/planner/inc/plannerInt.h
+20
-2
source/libs/planner/src/logicPlan.c
source/libs/planner/src/logicPlan.c
+276
-577
source/libs/planner/src/physicalPlan.c
source/libs/planner/src/physicalPlan.c
+480
-0
source/libs/planner/src/physicalPlanJson.c
source/libs/planner/src/physicalPlanJson.c
+0
-1227
source/libs/planner/src/planner.c
source/libs/planner/src/planner.c
+15
-1
source/libs/planner/src/plannerImpl.c
source/libs/planner/src/plannerImpl.c
+0
-868
source/libs/planner/test/phyPlanTests.cpp
source/libs/planner/test/phyPlanTests.cpp
+0
-208
source/libs/planner/test/plannerTest.cpp
source/libs/planner/test/plannerTest.cpp
+3
-2
source/libs/planner/test/plannerTestMain.cpp
source/libs/planner/test/plannerTestMain.cpp
+20
-19
source/libs/planner/test/plannerTests.cpp
source/libs/planner/test/plannerTests.cpp
+0
-107
未找到文件。
include/libs/nodes/plannodes.h
浏览文件 @
cd7a0e55
...
@@ -22,7 +22,6 @@ extern "C" {
...
@@ -22,7 +22,6 @@ extern "C" {
#include "querynodes.h"
#include "querynodes.h"
#include "query.h"
#include "query.h"
#include "tmsg.h"
typedef
struct
SLogicNode
{
typedef
struct
SLogicNode
{
ENodeType
type
;
ENodeType
type
;
...
...
include/libs/parser/parser.h
浏览文件 @
cd7a0e55
...
@@ -20,86 +20,7 @@
...
@@ -20,86 +20,7 @@
extern
"C"
{
extern
"C"
{
#endif
#endif
#if 0
#include "parsenodes.h"
typedef struct SParseContext {
uint64_t requestId;
int32_t acctId;
const char *db;
void *pTransporter;
SEpSet mgmtEpSet;
const char *pSql; // sql string
size_t sqlLen; // length of the sql string
char *pMsg; // extended error message if exists to help identifying the problem in sql statement.
int32_t msgLen; // max length of the msg
struct SCatalog *pCatalog;
} SParseContext;
/**
* Parse the sql statement and then return the SQueryStmtInfo as the result of bounded AST.
* @param pSql sql string
* @param length length of the sql string
* @param id operator id, generated by uuid generator
* @param msg extended error message if exists.
* @return error code
*/
int32_t qParseQuerySql(SParseContext* pContext, SQueryNode** pQueryNode);
/**
* Return true if it is a ddl/dcl sql statement
* @param pQuery
* @return
*/
bool qIsDdlQuery(const SQueryNode* pQueryNode);
/**
* Destroy logic query plan
* @param pQueryNode
*/
void qDestroyQuery(SQueryNode* pQueryNode);
/**
* Convert a normal sql statement to only query tags information to enable that the subscribe client can be aware quickly of the true vgroup ids that
* involved in the subscribe procedure.
* @param pSql
* @param length
* @param pConvertSql
* @return
*/
int32_t qParserConvertSql(const char* pStr, size_t length, char** pConvertSql);
void assignExprInfo(SExprInfo* dst, const SExprInfo* src);
void columnListCopy(SArray* dst, const SArray* src, uint64_t uid);
void columnListDestroy(SArray* pColumnList);
void dropAllExprInfo(SArray** pExprInfo, int32_t numOfLevel);
void dropOneLevelExprInfo(SArray* pExprInfo);
typedef struct SSourceParam {
SArray *pExprNodeList; //Array<struct tExprNode*>
SArray *pColumnList; //Array<struct SColumn>
int32_t num;
} SSourceParam;
SExprInfo* createExprInfo(STableMetaInfo* pTableMetaInfo, const char* funcName, SSourceParam* pSource, SSchema* pResSchema, int16_t interSize);
int32_t copyExprInfoList(SArray* dst, const SArray* src, uint64_t uid, bool deepcopy);
int32_t copyAllExprInfo(SArray* dst, const SArray* src, bool deepcopy);
int32_t getExprFunctionLevel(const SQueryStmtInfo* pQueryInfo);
STableMetaInfo* getMetaInfo(const SQueryStmtInfo* pQueryInfo, int32_t tableIndex);
SSchema *getOneColumnSchema(const STableMeta* pTableMeta, int32_t colIndex);
int32_t getNewResColId();
void addIntoSourceParam(SSourceParam* pSourceParam, tExprNode* pNode, SColumn* pColumn);
SExprInfo* createBinaryExprInfo(struct tExprNode* pNode, SSchema* pResSchema);
#else
#include "querynodes.h"
#include "querynodes.h"
#include "tmsg.h"
typedef
struct
SParseContext
{
typedef
struct
SParseContext
{
uint64_t
requestId
;
uint64_t
requestId
;
...
@@ -125,8 +46,6 @@ int32_t qParseQuerySql(SParseContext* pCxt, SQuery** pQuery);
...
@@ -125,8 +46,6 @@ int32_t qParseQuerySql(SParseContext* pCxt, SQuery** pQuery);
void
qDestroyQuery
(
SQuery
*
pQueryNode
);
void
qDestroyQuery
(
SQuery
*
pQueryNode
);
#endif
#ifdef __cplusplus
#ifdef __cplusplus
}
}
#endif
#endif
...
...
include/libs/planner/planner.h
浏览文件 @
cd7a0e55
...
@@ -20,199 +20,7 @@
...
@@ -20,199 +20,7 @@
extern
"C"
{
extern
"C"
{
#endif
#endif
#if 0
#include "query.h"
#include "tmsg.h"
#include "tarray.h"
#include "trpc.h"
#define QUERY_TYPE_MERGE 1
#define QUERY_TYPE_PARTIAL 2
#define QUERY_TYPE_SCAN 3
#define QUERY_TYPE_MODIFY 4
enum OPERATOR_TYPE_E {
OP_Unknown,
#define INCLUDE_AS_ENUM
#include "plannerOp.h"
#undef INCLUDE_AS_ENUM
OP_TotalNum
};
enum DATASINK_TYPE_E {
DSINK_Unknown,
DSINK_Dispatch,
DSINK_Insert,
DSINK_TotalNum
};
struct SEpSet;
struct SQueryStmtInfo;
typedef SSchema SSlotSchema;
typedef struct SDataBlockSchema {
SSlotSchema *pSchema;
int32_t numOfCols; // number of columns
int32_t resultRowSize;
int16_t precision;
} SDataBlockSchema;
typedef struct SQueryNodeBasicInfo {
int32_t type; // operator type
const char *name; // operator name
} SQueryNodeBasicInfo;
typedef struct SDataSink {
SQueryNodeBasicInfo info;
SDataBlockSchema schema;
} SDataSink;
typedef struct SDataDispatcher {
SDataSink sink;
} SDataDispatcher;
typedef struct SDataInserter {
SDataSink sink;
int32_t numOfTables;
uint32_t size;
char *pData;
} SDataInserter;
typedef struct SPhyNode {
SQueryNodeBasicInfo info;
SArray *pTargets; // target list to be computed or scanned at this node
SArray *pConditions; // implicitly-ANDed qual conditions
SDataBlockSchema targetSchema;
// children plan to generated result for current node to process
// in case of join, multiple plan nodes exist.
SArray *pChildren;
struct SPhyNode *pParent;
} SPhyNode;
typedef struct SScanPhyNode {
SPhyNode node;
uint64_t uid; // unique id of the table
int8_t tableType;
int32_t order; // scan order: TSDB_ORDER_ASC|TSDB_ORDER_DESC
int32_t count; // repeat count
int32_t reverse; // reverse scan count
} SScanPhyNode;
typedef SScanPhyNode SSystemTableScanPhyNode;
typedef SScanPhyNode STagScanPhyNode;
typedef struct STableScanPhyNode {
SScanPhyNode scan;
uint8_t scanFlag; // denotes reversed scan of data or not
STimeWindow window;
SArray *pTagsConditions; // implicitly-ANDed tag qual conditions
} STableScanPhyNode;
typedef STableScanPhyNode STableSeqScanPhyNode;
typedef struct SProjectPhyNode {
SPhyNode node;
} SProjectPhyNode;
typedef struct SDownstreamSource {
SQueryNodeAddr addr;
uint64_t taskId;
uint64_t schedId;
} SDownstreamSource;
typedef struct SExchangePhyNode {
SPhyNode node;
uint64_t srcTemplateId; // template id of datasource suplans
SArray *pSrcEndPoints; // SArray<SDownstreamSource>, scheduler fill by calling qSetSuplanExecutionNode
} SExchangePhyNode;
typedef enum EAggAlgo {
AGG_ALGO_PLAIN = 1, // simple agg across all input rows
AGG_ALGO_SORTED, // grouped agg, input must be sorted
AGG_ALGO_HASHED // grouped agg, use internal hashtable
} EAggAlgo;
typedef enum EAggSplit {
AGG_SPLIT_PRE = 1, // first level agg, maybe don't need calculate the final result
AGG_SPLIT_FINAL // second level agg, must calculate the final result
} EAggSplit;
typedef struct SAggPhyNode {
SPhyNode node;
EAggAlgo aggAlgo; // algorithm used by agg operator
EAggSplit aggSplit; // distributed splitting mode
SArray *pExprs; // SExprInfo list, these are expression list of group_by_clause and parameter expression of aggregate function
SArray *pGroupByList; // SColIndex list, but these must be column node
} SAggPhyNode;
typedef struct SSubplanId {
uint64_t queryId;
uint64_t templateId;
uint64_t subplanId;
} SSubplanId;
typedef struct SSubplan {
SSubplanId id; // unique id of the subplan
int32_t type; // QUERY_TYPE_MERGE|QUERY_TYPE_PARTIAL|QUERY_TYPE_SCAN|QUERY_TYPE_MODIFY
int32_t msgType; // message type for subplan, used to denote the send message type to vnode.
int32_t level; // the execution level of current subplan, starting from 0 in a top-down manner.
SQueryNodeAddr execNode; // for the scan/modify subplan, the optional execution node
SArray *pChildren; // the datasource subplan,from which to fetch the result
SArray *pParents; // the data destination subplan, get data from current subplan
SPhyNode *pNode; // physical plan of current subplan
SDataSink *pDataSink; // data of the subplan flow into the datasink
} SSubplan;
typedef struct SQueryDag {
uint64_t queryId;
int32_t numOfSubplans;
SArray *pSubplans; // SArray*<SArray*<SSubplan*>>. The execution level of subplan, starting from 0.
} SQueryDag;
struct SQueryNode;
/**
* Create the physical plan for the query, according to the AST.
* @param pQueryInfo
* @param pDag
* @param requestId
* @return
*/
int32_t qCreateQueryDag(const struct SQueryNode* pNode, struct SQueryDag** pDag, SSchema** pResSchema, int32_t* numOfCols, SArray* pNodeList, uint64_t requestId);
// Set datasource of this subplan, multiple calls may be made to a subplan.
// @subplan subplan to be schedule
// @templateId templateId of a group of datasource subplans of this @subplan
// @ep one execution location of this group of datasource subplans
void qSetSubplanExecutionNode(SSubplan* subplan, uint64_t templateId, SDownstreamSource* pSource);
int32_t qExplainQuery(const struct SQueryNode* pQueryInfo, struct SEpSet* pQnode, char** str);
/**
* Convert to subplan to string for the scheduler to send to the executor
*/
int32_t qSubPlanToString(const SSubplan* subplan, char** str, int32_t* len);
int32_t qStringToSubplan(const char* str, SSubplan** subplan);
void qDestroySubplan(SSubplan* pSubplan);
/**
* Destroy the physical plan.
* @param pQueryPhyNode
* @return
*/
void qDestroyQueryDag(SQueryDag* pDag);
char* qDagToString(const SQueryDag* pDag);
SQueryDag* qStringToDag(const char* pStr);
#else
#include "plannodes.h"
#include "plannodes.h"
#include "query.h"
#define QUERY_TYPE_MERGE 1
#define QUERY_TYPE_MERGE 1
#define QUERY_TYPE_PARTIAL 2
#define QUERY_TYPE_PARTIAL 2
...
@@ -266,8 +74,6 @@ SQueryPlan* qStringToQueryPlan(const char* pStr);
...
@@ -266,8 +74,6 @@ SQueryPlan* qStringToQueryPlan(const char* pStr);
void
qDestroyQueryPlan
(
SQueryPlan
*
pPlan
);
void
qDestroyQueryPlan
(
SQueryPlan
*
pPlan
);
#endif
#ifdef __cplusplus
#ifdef __cplusplus
}
}
#endif
#endif
...
...
source/client/src/clientImpl.c
浏览文件 @
cd7a0e55
...
@@ -198,20 +198,18 @@ int32_t execDdlQuery(SRequestObj* pRequest, SQuery* pQuery) {
...
@@ -198,20 +198,18 @@ int32_t execDdlQuery(SRequestObj* pRequest, SQuery* pQuery) {
int32_t
getPlan
(
SRequestObj
*
pRequest
,
SQuery
*
pQuery
,
SQueryPlan
**
pDag
,
SArray
*
pNodeList
)
{
int32_t
getPlan
(
SRequestObj
*
pRequest
,
SQuery
*
pQuery
,
SQueryPlan
**
pDag
,
SArray
*
pNodeList
)
{
// pRequest->type = pQuery->type;
// pRequest->type = pQuery->type;
// SSchema* pSchema = NULL;
SPlanContext
cxt
=
{
.
queryId
=
pRequest
->
requestId
,
.
pAstRoot
=
pQuery
->
pRoot
};
// int32_t numOfCols = 0;
int32_t
code
=
qCreateQueryPlan
(
&
cxt
,
pDag
);
// int32_t code = qCreateQueryDag(pQuery, pDag, &pSchema, &numOfCols, pNodeList, pRequest->requestId);
if
(
code
!=
0
)
{
// if (code != 0) {
return
code
;
// return code;
}
// }
// if (pQuery->type == TSDB_SQL_SELECT) {
// if (pQuery->type == TSDB_SQL_SELECT) {
// setResSchemaInfo(&pRequest->body.resInfo, pSchema, numOfCols);
// setResSchemaInfo(&pRequest->body.resInfo, pSchema, numOfCols);
// pRequest->type = TDMT_VND_QUERY;
// pRequest->type = TDMT_VND_QUERY;
// }
// }
// tfree(pSchema);
return
code
;
// return code;
}
}
void
setResSchemaInfo
(
SReqResultInfo
*
pResInfo
,
const
SSchema
*
pSchema
,
int32_t
numOfCols
)
{
void
setResSchemaInfo
(
SReqResultInfo
*
pResInfo
,
const
SSchema
*
pSchema
,
int32_t
numOfCols
)
{
...
...
source/libs/parser/inc/astCreateFuncs.h
浏览文件 @
cd7a0e55
...
@@ -20,11 +20,18 @@
...
@@ -20,11 +20,18 @@
extern
"C"
{
extern
"C"
{
#endif
#endif
#include "querynodes.h"
#include "nodesShowStmts.h"
#include "nodesShowStmts.h"
#include "astCreateContext.h"
#include "parser.h"
#include "querynodes.h"
#include "ttoken.h"
#include "ttoken.h"
typedef
struct
SAstCreateContext
{
SParseContext
*
pQueryCxt
;
bool
notSupport
;
bool
valid
;
SNode
*
pRootNode
;
}
SAstCreateContext
;
extern
SToken
nil_token
;
extern
SToken
nil_token
;
SNode
*
createRawExprNode
(
SAstCreateContext
*
pCxt
,
const
SToken
*
pToken
,
SNode
*
pNode
);
SNode
*
createRawExprNode
(
SAstCreateContext
*
pCxt
,
const
SToken
*
pToken
,
SNode
*
pNode
);
...
...
source/libs/parser/inc/parserI
mpl
.h
→
source/libs/parser/inc/parserI
nt
.h
浏览文件 @
cd7a0e55
...
@@ -13,8 +13,8 @@
...
@@ -13,8 +13,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
*/
#ifndef _TD_PARSER_I
MPL
_H_
#ifndef _TD_PARSER_I
NT
_H_
#define _TD_PARSER_I
MPL
_H_
#define _TD_PARSER_I
NT
_H_
#ifdef __cplusplus
#ifdef __cplusplus
extern
"C"
{
extern
"C"
{
...
@@ -24,10 +24,9 @@ extern "C" {
...
@@ -24,10 +24,9 @@ extern "C" {
int32_t
doParse
(
SParseContext
*
pParseCxt
,
SQuery
**
pQuery
);
int32_t
doParse
(
SParseContext
*
pParseCxt
,
SQuery
**
pQuery
);
int32_t
doTranslate
(
SParseContext
*
pParseCxt
,
SQuery
*
pQuery
);
int32_t
doTranslate
(
SParseContext
*
pParseCxt
,
SQuery
*
pQuery
);
int32_t
parseQuerySql
(
SParseContext
*
pCxt
,
SQuery
**
pQuery
);
#ifdef __cplusplus
#ifdef __cplusplus
}
}
#endif
#endif
#endif
/*_TD_PARSER_I
MPL
_H_*/
#endif
/*_TD_PARSER_I
NT
_H_*/
source/libs/parser/inc/parserUtil.h
浏览文件 @
cd7a0e55
...
@@ -13,8 +13,8 @@
...
@@ -13,8 +13,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
*/
#ifndef TDENGINE_PARSERUTIL_H
#ifndef TDENGINE_PARSER
_
UTIL_H
#define TDENGINE_PARSERUTIL_H
#define TDENGINE_PARSER
_
UTIL_H
#ifdef __cplusplus
#ifdef __cplusplus
extern
"C"
{
extern
"C"
{
...
@@ -22,7 +22,6 @@ extern "C" {
...
@@ -22,7 +22,6 @@ extern "C" {
#include "os.h"
#include "os.h"
#include "query.h"
#include "query.h"
#include "tmsg.h"
#include "ttoken.h"
#include "ttoken.h"
typedef
struct
SMsgBuf
{
typedef
struct
SMsgBuf
{
...
@@ -54,4 +53,4 @@ STableComInfo getTableInfo(const STableMeta* pTableMeta);
...
@@ -54,4 +53,4 @@ STableComInfo getTableInfo(const STableMeta* pTableMeta);
}
}
#endif
#endif
#endif // TDENGINE_PARSERUTIL_H
#endif // TDENGINE_PARSER
_
UTIL_H
source/libs/parser/src/astCreateContext.c
已删除
100644 → 0
浏览文件 @
768e0593
/*
* 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 "ttoken.h"
#include "astCreateContext.h"
int32_t
createAstCreateContext
(
SParseContext
*
pQueryCxt
,
SAstCreateContext
*
pCxt
)
{
pCxt
->
pQueryCxt
=
pQueryCxt
;
pCxt
->
notSupport
=
false
;
pCxt
->
valid
=
true
;
pCxt
->
pRootNode
=
NULL
;
return
TSDB_CODE_SUCCESS
;
}
int32_t
destroyAstCreateContext
(
SAstCreateContext
*
pCxt
)
{
return
TSDB_CODE_SUCCESS
;
}
source/libs/parser/src/astParse.c
0 → 100644
浏览文件 @
cd7a0e55
/*
* 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 "parserInt.h"
#include "astCreateFuncs.h"
#include "ttoken.h"
typedef
void
*
(
*
FMalloc
)(
size_t
);
typedef
void
(
*
FFree
)(
void
*
);
extern
void
*
NewParseAlloc
(
FMalloc
);
extern
void
NewParse
(
void
*
,
int
,
SToken
,
void
*
);
extern
void
NewParseFree
(
void
*
,
FFree
);
extern
void
NewParseTrace
(
FILE
*
,
char
*
);
static
uint32_t
toNewTokenId
(
uint32_t
tokenId
)
{
switch
(
tokenId
)
{
case
TK_OR
:
return
NEW_TK_OR
;
case
TK_AND
:
return
NEW_TK_AND
;
case
TK_UNION
:
return
NEW_TK_UNION
;
case
TK_ALL
:
return
NEW_TK_ALL
;
case
TK_MINUS
:
return
NEW_TK_NK_MINUS
;
case
TK_PLUS
:
return
NEW_TK_NK_PLUS
;
case
TK_STAR
:
return
NEW_TK_NK_STAR
;
case
TK_SLASH
:
return
NEW_TK_NK_SLASH
;
case
TK_REM
:
return
NEW_TK_NK_REM
;
case
TK_SHOW
:
return
NEW_TK_SHOW
;
case
TK_DATABASES
:
return
NEW_TK_DATABASES
;
case
TK_INTEGER
:
return
NEW_TK_NK_INTEGER
;
case
TK_FLOAT
:
return
NEW_TK_NK_FLOAT
;
case
TK_STRING
:
return
NEW_TK_NK_STRING
;
case
TK_BOOL
:
return
NEW_TK_NK_BOOL
;
case
TK_TIMESTAMP
:
return
NEW_TK_TIMESTAMP
;
case
TK_VARIABLE
:
return
NEW_TK_NK_VARIABLE
;
case
TK_COMMA
:
return
NEW_TK_NK_COMMA
;
case
TK_ID
:
return
NEW_TK_NK_ID
;
case
TK_LP
:
return
NEW_TK_NK_LP
;
case
TK_RP
:
return
NEW_TK_NK_RP
;
case
TK_DOT
:
return
NEW_TK_NK_DOT
;
case
TK_BETWEEN
:
return
NEW_TK_BETWEEN
;
case
TK_NOT
:
return
NEW_TK_NOT
;
case
TK_IS
:
return
NEW_TK_IS
;
case
TK_NULL
:
return
NEW_TK_NULL
;
case
TK_LT
:
return
NEW_TK_NK_LT
;
case
TK_GT
:
return
NEW_TK_NK_GT
;
case
TK_LE
:
return
NEW_TK_NK_LE
;
case
TK_GE
:
return
NEW_TK_NK_GE
;
case
TK_NE
:
return
NEW_TK_NK_NE
;
case
TK_EQ
:
return
NEW_TK_NK_EQ
;
case
TK_LIKE
:
return
NEW_TK_LIKE
;
case
TK_MATCH
:
return
NEW_TK_MATCH
;
case
TK_NMATCH
:
return
NEW_TK_NMATCH
;
case
TK_IN
:
return
NEW_TK_IN
;
case
TK_SELECT
:
return
NEW_TK_SELECT
;
case
TK_DISTINCT
:
return
NEW_TK_DISTINCT
;
case
TK_WHERE
:
return
NEW_TK_WHERE
;
case
TK_AS
:
return
NEW_TK_AS
;
case
TK_FROM
:
return
NEW_TK_FROM
;
case
TK_JOIN
:
return
NEW_TK_JOIN
;
// case TK_PARTITION:
// return NEW_TK_PARTITION;
case
TK_SESSION
:
return
NEW_TK_SESSION
;
case
TK_STATE_WINDOW
:
return
NEW_TK_STATE_WINDOW
;
case
TK_INTERVAL
:
return
NEW_TK_INTERVAL
;
case
TK_SLIDING
:
return
NEW_TK_SLIDING
;
case
TK_FILL
:
return
NEW_TK_FILL
;
// case TK_VALUE:
// return NEW_TK_VALUE;
case
TK_NONE
:
return
NEW_TK_NONE
;
case
TK_PREV
:
return
NEW_TK_PREV
;
case
TK_LINEAR
:
return
NEW_TK_LINEAR
;
// case TK_NEXT:
// return NEW_TK_NEXT;
case
TK_GROUP
:
return
NEW_TK_GROUP
;
case
TK_HAVING
:
return
NEW_TK_HAVING
;
case
TK_ORDER
:
return
NEW_TK_ORDER
;
case
TK_BY
:
return
NEW_TK_BY
;
case
TK_ASC
:
return
NEW_TK_ASC
;
case
TK_DESC
:
return
NEW_TK_DESC
;
case
TK_SLIMIT
:
return
NEW_TK_SLIMIT
;
case
TK_SOFFSET
:
return
NEW_TK_SOFFSET
;
case
TK_LIMIT
:
return
NEW_TK_LIMIT
;
case
TK_OFFSET
:
return
NEW_TK_OFFSET
;
case
TK_SPACE
:
case
NEW_TK_ON
:
case
NEW_TK_INNER
:
break
;
default:
printf
(
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!tokenId = %d
\n
"
,
tokenId
);
}
return
tokenId
;
}
static
uint32_t
getToken
(
const
char
*
z
,
uint32_t
*
tokenId
)
{
uint32_t
n
=
tGetToken
(
z
,
tokenId
);
*
tokenId
=
toNewTokenId
(
*
tokenId
);
return
n
;
}
static
bool
isCmd
(
const
SNode
*
pRootNode
)
{
if
(
NULL
==
pRootNode
)
{
return
true
;
}
switch
(
nodeType
(
pRootNode
))
{
case
QUERY_NODE_SELECT_STMT
:
return
false
;
default:
break
;
}
return
true
;
}
int32_t
doParse
(
SParseContext
*
pParseCxt
,
SQuery
**
pQuery
)
{
SAstCreateContext
cxt
=
{
.
pQueryCxt
=
pParseCxt
,
.
notSupport
=
false
,
.
valid
=
true
,
.
pRootNode
=
NULL
};
void
*
pParser
=
NewParseAlloc
(
malloc
);
int32_t
i
=
0
;
while
(
1
)
{
SToken
t0
=
{
0
};
if
(
cxt
.
pQueryCxt
->
pSql
[
i
]
==
0
)
{
NewParse
(
pParser
,
0
,
t0
,
&
cxt
);
goto
abort_parse
;
}
t0
.
n
=
getToken
((
char
*
)
&
cxt
.
pQueryCxt
->
pSql
[
i
],
&
t0
.
type
);
t0
.
z
=
(
char
*
)(
cxt
.
pQueryCxt
->
pSql
+
i
);
i
+=
t0
.
n
;
switch
(
t0
.
type
)
{
case
TK_SPACE
:
case
TK_COMMENT
:
{
break
;
}
case
TK_SEMI
:
{
NewParse
(
pParser
,
0
,
t0
,
&
cxt
);
goto
abort_parse
;
}
case
TK_QUESTION
:
case
TK_ILLEGAL
:
{
snprintf
(
cxt
.
pQueryCxt
->
pMsg
,
cxt
.
pQueryCxt
->
msgLen
,
"unrecognized token:
\"
%s
\"
"
,
t0
.
z
);
cxt
.
valid
=
false
;
goto
abort_parse
;
}
case
TK_HEX
:
case
TK_OCT
:
case
TK_BIN
:
{
snprintf
(
cxt
.
pQueryCxt
->
pMsg
,
cxt
.
pQueryCxt
->
msgLen
,
"unsupported token:
\"
%s
\"
"
,
t0
.
z
);
cxt
.
valid
=
false
;
goto
abort_parse
;
}
default:
NewParse
(
pParser
,
t0
.
type
,
t0
,
&
cxt
);
// NewParseTrace(stdout, "");
if
(
!
cxt
.
valid
)
{
goto
abort_parse
;
}
}
}
abort_parse:
NewParseFree
(
pParser
,
free
);
if
(
cxt
.
valid
)
{
*
pQuery
=
calloc
(
1
,
sizeof
(
SQuery
));
(
*
pQuery
)
->
isCmd
=
isCmd
(
cxt
.
pRootNode
);
(
*
pQuery
)
->
pRoot
=
cxt
.
pRootNode
;
}
return
cxt
.
valid
?
TSDB_CODE_SUCCESS
:
TSDB_CODE_FAILED
;
}
source/libs/parser/src/
parserImpl
.c
→
source/libs/parser/src/
astTranslate
.c
浏览文件 @
cd7a0e55
...
@@ -13,238 +13,12 @@
...
@@ -13,238 +13,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
*/
#include "parserI
mpl
.h"
#include "parserI
nt
.h"
#include "astCreateContext.h"
#include "catalog.h"
#include "catalog.h"
#include "functionMgt.h"
#include "functionMgt.h"
#include "parserUtil.h"
#include "parserUtil.h"
#include "tglobal.h"
#include "tname.h"
#include "ttime.h"
#include "ttime.h"
#include "ttoken.h"
typedef
void
*
(
*
FMalloc
)(
size_t
);
typedef
void
(
*
FFree
)(
void
*
);
extern
void
*
NewParseAlloc
(
FMalloc
);
extern
void
NewParse
(
void
*
,
int
,
SToken
,
void
*
);
extern
void
NewParseFree
(
void
*
,
FFree
);
extern
void
NewParseTrace
(
FILE
*
,
char
*
);
static
uint32_t
toNewTokenId
(
uint32_t
tokenId
)
{
switch
(
tokenId
)
{
case
TK_OR
:
return
NEW_TK_OR
;
case
TK_AND
:
return
NEW_TK_AND
;
case
TK_UNION
:
return
NEW_TK_UNION
;
case
TK_ALL
:
return
NEW_TK_ALL
;
case
TK_MINUS
:
return
NEW_TK_NK_MINUS
;
case
TK_PLUS
:
return
NEW_TK_NK_PLUS
;
case
TK_STAR
:
return
NEW_TK_NK_STAR
;
case
TK_SLASH
:
return
NEW_TK_NK_SLASH
;
case
TK_REM
:
return
NEW_TK_NK_REM
;
case
TK_SHOW
:
return
NEW_TK_SHOW
;
case
TK_DATABASES
:
return
NEW_TK_DATABASES
;
case
TK_INTEGER
:
return
NEW_TK_NK_INTEGER
;
case
TK_FLOAT
:
return
NEW_TK_NK_FLOAT
;
case
TK_STRING
:
return
NEW_TK_NK_STRING
;
case
TK_BOOL
:
return
NEW_TK_NK_BOOL
;
case
TK_TIMESTAMP
:
return
NEW_TK_TIMESTAMP
;
case
TK_VARIABLE
:
return
NEW_TK_NK_VARIABLE
;
case
TK_COMMA
:
return
NEW_TK_NK_COMMA
;
case
TK_ID
:
return
NEW_TK_NK_ID
;
case
TK_LP
:
return
NEW_TK_NK_LP
;
case
TK_RP
:
return
NEW_TK_NK_RP
;
case
TK_DOT
:
return
NEW_TK_NK_DOT
;
case
TK_BETWEEN
:
return
NEW_TK_BETWEEN
;
case
TK_NOT
:
return
NEW_TK_NOT
;
case
TK_IS
:
return
NEW_TK_IS
;
case
TK_NULL
:
return
NEW_TK_NULL
;
case
TK_LT
:
return
NEW_TK_NK_LT
;
case
TK_GT
:
return
NEW_TK_NK_GT
;
case
TK_LE
:
return
NEW_TK_NK_LE
;
case
TK_GE
:
return
NEW_TK_NK_GE
;
case
TK_NE
:
return
NEW_TK_NK_NE
;
case
TK_EQ
:
return
NEW_TK_NK_EQ
;
case
TK_LIKE
:
return
NEW_TK_LIKE
;
case
TK_MATCH
:
return
NEW_TK_MATCH
;
case
TK_NMATCH
:
return
NEW_TK_NMATCH
;
case
TK_IN
:
return
NEW_TK_IN
;
case
TK_SELECT
:
return
NEW_TK_SELECT
;
case
TK_DISTINCT
:
return
NEW_TK_DISTINCT
;
case
TK_WHERE
:
return
NEW_TK_WHERE
;
case
TK_AS
:
return
NEW_TK_AS
;
case
TK_FROM
:
return
NEW_TK_FROM
;
case
TK_JOIN
:
return
NEW_TK_JOIN
;
// case TK_PARTITION:
// return NEW_TK_PARTITION;
case
TK_SESSION
:
return
NEW_TK_SESSION
;
case
TK_STATE_WINDOW
:
return
NEW_TK_STATE_WINDOW
;
case
TK_INTERVAL
:
return
NEW_TK_INTERVAL
;
case
TK_SLIDING
:
return
NEW_TK_SLIDING
;
case
TK_FILL
:
return
NEW_TK_FILL
;
// case TK_VALUE:
// return NEW_TK_VALUE;
case
TK_NONE
:
return
NEW_TK_NONE
;
case
TK_PREV
:
return
NEW_TK_PREV
;
case
TK_LINEAR
:
return
NEW_TK_LINEAR
;
// case TK_NEXT:
// return NEW_TK_NEXT;
case
TK_GROUP
:
return
NEW_TK_GROUP
;
case
TK_HAVING
:
return
NEW_TK_HAVING
;
case
TK_ORDER
:
return
NEW_TK_ORDER
;
case
TK_BY
:
return
NEW_TK_BY
;
case
TK_ASC
:
return
NEW_TK_ASC
;
case
TK_DESC
:
return
NEW_TK_DESC
;
case
TK_SLIMIT
:
return
NEW_TK_SLIMIT
;
case
TK_SOFFSET
:
return
NEW_TK_SOFFSET
;
case
TK_LIMIT
:
return
NEW_TK_LIMIT
;
case
TK_OFFSET
:
return
NEW_TK_OFFSET
;
case
TK_SPACE
:
case
NEW_TK_ON
:
case
NEW_TK_INNER
:
break
;
default:
printf
(
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!tokenId = %d
\n
"
,
tokenId
);
}
return
tokenId
;
}
static
uint32_t
getToken
(
const
char
*
z
,
uint32_t
*
tokenId
)
{
uint32_t
n
=
tGetToken
(
z
,
tokenId
);
*
tokenId
=
toNewTokenId
(
*
tokenId
);
return
n
;
}
static
bool
isCmd
(
const
SNode
*
pRootNode
)
{
if
(
NULL
==
pRootNode
)
{
return
true
;
}
switch
(
nodeType
(
pRootNode
))
{
case
QUERY_NODE_SELECT_STMT
:
return
false
;
default:
break
;
}
return
true
;
}
int32_t
doParse
(
SParseContext
*
pParseCxt
,
SQuery
**
pQuery
)
{
SAstCreateContext
cxt
;
createAstCreateContext
(
pParseCxt
,
&
cxt
);
void
*
pParser
=
NewParseAlloc
(
malloc
);
int32_t
i
=
0
;
while
(
1
)
{
SToken
t0
=
{
0
};
if
(
cxt
.
pQueryCxt
->
pSql
[
i
]
==
0
)
{
NewParse
(
pParser
,
0
,
t0
,
&
cxt
);
goto
abort_parse
;
}
t0
.
n
=
getToken
((
char
*
)
&
cxt
.
pQueryCxt
->
pSql
[
i
],
&
t0
.
type
);
t0
.
z
=
(
char
*
)(
cxt
.
pQueryCxt
->
pSql
+
i
);
i
+=
t0
.
n
;
switch
(
t0
.
type
)
{
case
TK_SPACE
:
case
TK_COMMENT
:
{
break
;
}
case
TK_SEMI
:
{
NewParse
(
pParser
,
0
,
t0
,
&
cxt
);
goto
abort_parse
;
}
case
TK_QUESTION
:
case
TK_ILLEGAL
:
{
snprintf
(
cxt
.
pQueryCxt
->
pMsg
,
cxt
.
pQueryCxt
->
msgLen
,
"unrecognized token:
\"
%s
\"
"
,
t0
.
z
);
cxt
.
valid
=
false
;
goto
abort_parse
;
}
case
TK_HEX
:
case
TK_OCT
:
case
TK_BIN
:
{
snprintf
(
cxt
.
pQueryCxt
->
pMsg
,
cxt
.
pQueryCxt
->
msgLen
,
"unsupported token:
\"
%s
\"
"
,
t0
.
z
);
cxt
.
valid
=
false
;
goto
abort_parse
;
}
default:
NewParse
(
pParser
,
t0
.
type
,
t0
,
&
cxt
);
// NewParseTrace(stdout, "");
if
(
!
cxt
.
valid
)
{
goto
abort_parse
;
}
}
}
abort_parse:
NewParseFree
(
pParser
,
free
);
destroyAstCreateContext
(
&
cxt
);
if
(
cxt
.
valid
)
{
*
pQuery
=
calloc
(
1
,
sizeof
(
SQuery
));
(
*
pQuery
)
->
isCmd
=
isCmd
(
cxt
.
pRootNode
);
(
*
pQuery
)
->
pRoot
=
cxt
.
pRootNode
;
}
return
cxt
.
valid
?
TSDB_CODE_SUCCESS
:
TSDB_CODE_FAILED
;
}
static
bool
afterGroupBy
(
ESqlClause
clause
)
{
static
bool
afterGroupBy
(
ESqlClause
clause
)
{
return
clause
>
SQL_CLAUSE_GROUP_BY
;
return
clause
>
SQL_CLAUSE_GROUP_BY
;
...
@@ -1064,11 +838,3 @@ int32_t doTranslate(SParseContext* pParseCxt, SQuery* pQuery) {
...
@@ -1064,11 +838,3 @@ int32_t doTranslate(SParseContext* pParseCxt, SQuery* pQuery) {
}
}
return
code
;
return
code
;
}
}
int32_t
parseQuerySql
(
SParseContext
*
pCxt
,
SQuery
**
pQuery
)
{
int32_t
code
=
doParse
(
pCxt
,
pQuery
);
if
(
TSDB_CODE_SUCCESS
==
code
)
{
code
=
doTranslate
(
pCxt
,
*
pQuery
);
}
return
code
;
}
source/libs/parser/src/parser.c
浏览文件 @
cd7a0e55
...
@@ -267,7 +267,7 @@ void qDestroyQuery(SQueryNode* pQueryNode) {
...
@@ -267,7 +267,7 @@ void qDestroyQuery(SQueryNode* pQueryNode) {
#include "parser.h"
#include "parser.h"
#include "insertParser.h"
#include "insertParser.h"
#include "parserI
mpl
.h"
#include "parserI
nt
.h"
#include "ttoken.h"
#include "ttoken.h"
static
bool
isInsertSql
(
const
char
*
pStr
,
size_t
length
)
{
static
bool
isInsertSql
(
const
char
*
pStr
,
size_t
length
)
{
...
@@ -281,11 +281,19 @@ static bool isInsertSql(const char* pStr, size_t length) {
...
@@ -281,11 +281,19 @@ static bool isInsertSql(const char* pStr, size_t length) {
}
while
(
1
);
}
while
(
1
);
}
}
static
int32_t
parseSqlIntoAst
(
SParseContext
*
pCxt
,
SQuery
**
pQuery
)
{
int32_t
code
=
doParse
(
pCxt
,
pQuery
);
if
(
TSDB_CODE_SUCCESS
==
code
)
{
code
=
doTranslate
(
pCxt
,
*
pQuery
);
}
return
code
;
}
int32_t
qParseQuerySql
(
SParseContext
*
pCxt
,
SQuery
**
pQuery
)
{
int32_t
qParseQuerySql
(
SParseContext
*
pCxt
,
SQuery
**
pQuery
)
{
if
(
isInsertSql
(
pCxt
->
pSql
,
pCxt
->
sqlLen
))
{
if
(
isInsertSql
(
pCxt
->
pSql
,
pCxt
->
sqlLen
))
{
return
parseInsertSql
(
pCxt
,
pQuery
);
return
parseInsertSql
(
pCxt
,
pQuery
);
}
else
{
}
else
{
return
parse
QuerySql
(
pCxt
,
pQuery
);
return
parse
SqlIntoAst
(
pCxt
,
pQuery
);
}
}
}
}
...
...
source/libs/parser/test/
newP
arserTest.cpp
→
source/libs/parser/test/
p
arserTest.cpp
浏览文件 @
cd7a0e55
...
@@ -18,7 +18,7 @@
...
@@ -18,7 +18,7 @@
#include <gtest/gtest.h>
#include <gtest/gtest.h>
#include "parserI
mpl
.h"
#include "parserI
nt
.h"
using
namespace
std
;
using
namespace
std
;
using
namespace
testing
;
using
namespace
testing
;
...
...
source/libs/planner/inc/plannerI
mpl
.h
→
source/libs/planner/inc/plannerI
nt
.h
浏览文件 @
cd7a0e55
...
@@ -20,11 +20,29 @@
...
@@ -20,11 +20,29 @@
extern
"C"
{
extern
"C"
{
#endif
#endif
#include "plannodes.h"
#include "planner.h"
#include "planner.h"
int32_t
createLogicPlan
(
SNode
*
pNode
,
SLogicNode
**
pLogicNode
);
#define CHECK_ALLOC(p, res) \
do { \
if (NULL == (p)) { \
pCxt->errCode = TSDB_CODE_OUT_OF_MEMORY; \
return (res); \
} \
} while (0)
#define CHECK_CODE(exec, res) \
do { \
int32_t code = (exec); \
if (TSDB_CODE_SUCCESS != code) { \
pCxt->errCode = code; \
return (res); \
} \
} while (0)
int32_t
createLogicPlan
(
SPlanContext
*
pCxt
,
SLogicNode
**
pLogicNode
);
int32_t
optimize
(
SPlanContext
*
pCxt
,
SLogicNode
*
pLogicNode
);
int32_t
createPhysiPlan
(
SLogicNode
*
pLogicNode
,
SPhysiNode
**
pPhyNode
);
int32_t
createPhysiPlan
(
SLogicNode
*
pLogicNode
,
SPhysiNode
**
pPhyNode
);
int32_t
buildPhysiPlan
(
SPlanContext
*
pCxt
,
SLogicNode
*
pLogicNode
,
SQueryPlan
**
pPlan
);
#ifdef __cplusplus
#ifdef __cplusplus
}
}
...
...
source/libs/planner/src/logicPlan.c
浏览文件 @
cd7a0e55
...
@@ -13,658 +13,357 @@
...
@@ -13,658 +13,357 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
*/
#if 0
#include <function.h>
#include "function.h"
#include "os.h"
#include "parser.h"
#include "plannerInt.h"
#include "plannerInt.h"
typedef struct SFillEssInfo {
#include "functionMgt.h"
int32_t fillType; // fill type
int64_t *val; // fill value
typedef
struct
SLogicPlanContext
{
} SFillEssInfo;
int32_t
errCode
;
int32_t
planNodeId
;
typedef struct SJoinCond {
}
SLogicPlanContext
;
bool tagExists; // denote if tag condition exists or not
SColumn *tagCond[2];
static
SLogicNode
*
createQueryLogicNode
(
SLogicPlanContext
*
pCxt
,
SNode
*
pStmt
);
SColumn *colCond[2];
static
SLogicNode
*
createLogicNodeByTable
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
,
SNode
*
pTable
);
} SJoinCond;
typedef
struct
SRewriteExprCxt
{
static SArray* createQueryPlanImpl(const SQueryStmtInfo* pQueryInfo);
int32_t
errCode
;
static void doDestroyQueryNode(SQueryPlanNode* pQueryNode);
SNodeList
*
pExprs
;
}
SRewriteExprCxt
;
int32_t printExprInfo(char* buf, const SQueryPlanNode* pQueryNode, int32_t len);
int32_t optimizeQueryPlan(struct SQueryPlanNode* pQueryNode) {
static
EDealRes
doRewriteExpr
(
SNode
**
pNode
,
void
*
pContext
)
{
return 0;
switch
(
nodeType
(
*
pNode
))
{
}
case
QUERY_NODE_OPERATOR
:
case
QUERY_NODE_LOGIC_CONDITION
:
static int32_t createModificationOpPlan(const SQueryNode* pNode, SQueryPlanNode** pQueryPlan) {
case
QUERY_NODE_FUNCTION
:
{
SVnodeModifOpStmtInfo* pModifStmtInfo = (SVnodeModifOpStmtInfo*)pNode;
SRewriteExprCxt
*
pCxt
=
(
SRewriteExprCxt
*
)
pContext
;
SNode
*
pExpr
;
*pQueryPlan = calloc(1, sizeof(SQueryPlanNode));
int32_t
index
=
0
;
SArray* blocks = taosArrayInit(taosArrayGetSize(pModifStmtInfo->pDataBlocks), POINTER_BYTES);
FOREACH
(
pExpr
,
pCxt
->
pExprs
)
{
if
(
QUERY_NODE_GROUPING_SET
==
nodeType
(
pExpr
))
{
SDataPayloadInfo* pPayload = calloc(1, sizeof(SDataPayloadInfo));
pExpr
=
nodesListGetNode
(((
SGroupingSetNode
*
)
pExpr
)
->
pParameterList
,
0
);
if (NULL == *pQueryPlan || NULL == blocks || NULL == pPayload) {
}
return TSDB_CODE_TSC_OUT_OF_MEMORY;
if
(
nodesEqualNode
(
pExpr
,
*
pNode
))
{
}
SColumnNode
*
pCol
=
(
SColumnNode
*
)
nodesMakeNode
(
QUERY_NODE_COLUMN
);
CHECK_ALLOC
(
pCol
,
DEAL_RES_ERROR
);
(*pQueryPlan)->info.type = QNODE_MODIFY;
SExprNode
*
pToBeRewrittenExpr
=
(
SExprNode
*
)(
*
pNode
);
taosArrayAddAll(blocks, pModifStmtInfo->pDataBlocks);
pCol
->
node
.
resType
=
pToBeRewrittenExpr
->
resType
;
strcpy
(
pCol
->
node
.
aliasName
,
pToBeRewrittenExpr
->
aliasName
);
if (pNode->type == TSDB_SQL_INSERT) {
strcpy
(
pCol
->
colName
,
((
SExprNode
*
)
pExpr
)
->
aliasName
);
pPayload->msgType = TDMT_VND_SUBMIT;
nodesDestroyNode
(
*
pNode
);
} else if (pNode->type == TSDB_SQL_CREATE_TABLE) {
*
pNode
=
(
SNode
*
)
pCol
;
pPayload->msgType = TDMT_VND_CREATE_TABLE;
return
DEAL_RES_IGNORE_CHILD
;
}
++
index
;
}
break
;
}
default:
break
;
}
}
pPayload->payload = blocks;
return
DEAL_RES_CONTINUE
;
(*pQueryPlan)->pExtInfo = pPayload;
return TSDB_CODE_SUCCESS;
}
}
int32_t createSelectPlan(const SQueryStmtInfo* pSelect, SQueryPlanNode** pQueryPlan)
{
typedef
struct
SNameExprCxt
{
SArray* pDownstream = createQueryPlanImpl(pSelect)
;
int32_t
planNodeId
;
assert(taosArrayGetSize(pDownstream) == 1)
;
int32_t
rewriteId
;
}
SNameExprCxt
;
*pQueryPlan = taosArrayGetP(pDownstream, 0);
taosArrayDestroy(pDownstream);
static
EDealRes
doNameExpr
(
SNode
*
pNode
,
void
*
pContext
)
{
return TSDB_CODE_SUCCESS;
switch
(
nodeType
(
pNode
))
{
}
case
QUERY_NODE_OPERATOR
:
case
QUERY_NODE_LOGIC_CONDITION
:
int32_t createQueryPlan(const SQueryNode* pNode, SQueryPlanNode** pQueryPlan)
{
case
QUERY_NODE_FUNCTION
:
{
switch (queryNodeType(pNode)) {
SNameExprCxt
*
pCxt
=
(
SNameExprCxt
*
)
pContext
;
case TSDB_SQL_SELECT: {
sprintf
(((
SExprNode
*
)
pNode
)
->
aliasName
,
"#expr_%d_%d"
,
pCxt
->
planNodeId
,
pCxt
->
rewriteId
++
);
return
createSelectPlan((const SQueryStmtInfo*)pNode, pQueryPlan)
;
return
DEAL_RES_IGNORE_CHILD
;
}
}
case TSDB_SQL_INSERT:
case TSDB_SQL_CREATE_TABLE:
return createModificationOpPlan(pNode, pQueryPlan);
default:
default:
return TSDB_CODE_FAILED
;
break
;
}
}
}
int32_t queryPlanToSql(struct SQueryPlanNode* pQueryNode, char** sql) {
return
DEAL_RES_CONTINUE
;
return 0;
}
}
void destroyQueryPlan(SQueryPlanNode* pQueryNod
e) {
static
int32_t
rewriteExpr
(
int32_t
planNodeId
,
int32_t
rewriteId
,
SNodeList
*
pExprs
,
SSelectStmt
*
pSelect
,
ESqlClause
claus
e
)
{
if (pQueryNode == NULL) {
SNameExprCxt
nameCxt
=
{
.
planNodeId
=
planNodeId
,
.
rewriteId
=
rewriteId
};
return
;
nodesWalkList
(
pExprs
,
doNameExpr
,
&
nameCxt
)
;
}
SRewriteExprCxt
cxt
=
{
.
errCode
=
TSDB_CODE_SUCCESS
,
.
pExprs
=
pExprs
};
nodesRewriteSelectStmt
(
pSelect
,
clause
,
doRewriteExpr
,
&
cxt
);
doDestroyQueryNode(pQueryNode)
;
return
cxt
.
errCode
;
}
}
//======================================================================================================================
static
SLogicNode
*
pushLogicNode
(
SLogicPlanContext
*
pCxt
,
SLogicNode
*
pRoot
,
SLogicNode
*
pNode
)
{
if
(
TSDB_CODE_SUCCESS
!=
pCxt
->
errCode
)
{
static SQueryPlanNode* createQueryNode(int32_t type, const char* name, SQueryPlanNode** pChildrenNode, int32_t numOfChildren,
goto
error
;
SExprInfo** pExpr, int32_t numOfOutput, const void* pExtInfo) {
SQueryPlanNode* pNode = calloc(1, sizeof(SQueryPlanNode));
pNode->info.type = type;
pNode->info.name = strdup(name);
pNode->numOfExpr = numOfOutput;
pNode->pExpr = taosArrayInit(numOfOutput, POINTER_BYTES);
taosArrayAddBatch(pNode->pExpr, pExpr, numOfOutput);
assert(pNode->numOfExpr == numOfOutput);
pNode->pChildren = taosArrayInit(4, POINTER_BYTES);
for(int32_t i = 0; i < numOfChildren; ++i) {
taosArrayPush(pNode->pChildren, &pChildrenNode[i]);
}
}
switch(type) {
if
(
NULL
==
pRoot
)
{
case QNODE_TAGSCAN:
case QNODE_STREAMSCAN:
case QNODE_TABLESCAN: {
SQueryTableInfo* info = calloc(1, sizeof(SQueryTableInfo));
memcpy(info, pExtInfo, sizeof(SQueryTableInfo));
info->tableName = strdup(((SQueryTableInfo*) pExtInfo)->tableName);
pNode->pExtInfo = info;
break;
}
case QNODE_TIMEWINDOW: {
SInterval* pInterval = calloc(1, sizeof(SInterval));
pNode->pExtInfo = pInterval;
memcpy(pInterval, pExtInfo, sizeof(SInterval));
break;
}
case QNODE_STATEWINDOW: {
SColumn* psw = calloc(1, sizeof(SColumn));
pNode->pExtInfo = psw;
memcpy(psw, pExtInfo, sizeof(SColumn));
break;
}
case QNODE_SESSIONWINDOW: {
SSessionWindow *pSessionWindow = calloc(1, sizeof(SSessionWindow));
pNode->pExtInfo = pSessionWindow;
memcpy(pSessionWindow, pExtInfo, sizeof(struct SSessionWindow));
break;
}
case QNODE_GROUPBY: {
SGroupbyExpr* p = (SGroupbyExpr*) pExtInfo;
SGroupbyExpr* pGroupbyExpr = calloc(1, sizeof(SGroupbyExpr));
pGroupbyExpr->groupbyTag = p->groupbyTag;
pGroupbyExpr->columnInfo = taosArrayDup(p->columnInfo);
pNode->pExtInfo = pGroupbyExpr;
break;
}
case QNODE_FILL: { // todo !!
pNode->pExtInfo = (void*)pExtInfo;
break;
}
case QNODE_LIMIT: {
pNode->pExtInfo = calloc(1, sizeof(SLimit));
memcpy(pNode->pExtInfo, pExtInfo, sizeof(SLimit));
break;
}
case QNODE_SORT: {
pNode->pExtInfo = taosArrayDup(pExtInfo);
break;
}
default:
break;
}
return pNode;
}
static SQueryPlanNode* doAddTableColumnNode(const SQueryStmtInfo* pQueryInfo, SQueryTableInfo* info, SArray* pExprs, SArray* tableCols) {
if (pQueryInfo->info.onlyTagQuery) {
int32_t num = (int32_t) taosArrayGetSize(pExprs);
SQueryPlanNode* pNode = createQueryNode(QNODE_TAGSCAN, "TableTagScan", NULL, 0, pExprs->pData, num, info);
if (pQueryInfo->info.distinct) {
pNode = createQueryNode(QNODE_DISTINCT, "Distinct", &pNode, 1, pExprs->pData, num, NULL);
}
return
pNode
;
return
pNode
;
}
}
SQueryPlanNode* pNode = NULL;
if
(
NULL
==
pNode
)
{
if (pQueryInfo->info.continueQuery) {
return
pRoot
;
pNode = createQueryNode(QNODE_STREAMSCAN, "StreamScan", NULL, 0, NULL, 0, info);
} else {
pNode = createQueryNode(QNODE_TABLESCAN, "TableScan", NULL, 0, NULL, 0, info);
}
}
if (!pQueryInfo->info.projectionQuery) {
if
(
NULL
==
pNode
->
pChildren
)
{
SArray* p = pQueryInfo->exprList[0];
pNode
->
pChildren
=
nodesMakeList
();
if
(
NULL
==
pNode
->
pChildren
)
{
// table source column projection, generate the projection expr
goto
error
;
int32_t numOfCols = (int32_t) taosArrayGetSize(tableCols);
pNode->numOfExpr = numOfCols;
pNode->pExpr = taosArrayInit(numOfCols, POINTER_BYTES);
for(int32_t i = 0; i < numOfCols; ++i) {
SExprInfo* pExprInfo = taosArrayGetP(p, i);
SColumn* pCol = pExprInfo->base.pColumns;
SSchema schema = createSchema(pCol->info.type, pCol->info.bytes, pCol->info.colId, pCol->name);
tExprNode* pExprNode = pExprInfo->pExpr->_function.pChild[0];
SExprInfo* px = createBinaryExprInfo(pExprNode, &schema);
taosArrayPush(pNode->pExpr, &px);
}
}
}
}
if
(
TSDB_CODE_SUCCESS
!=
nodesListAppend
(
pNode
->
pChildren
,
(
SNode
*
)
pRoot
))
{
goto
error
;
}
pRoot
->
pParent
=
pNode
;
return
pNode
;
return
pNode
;
error:
nodesDestroyNode
((
SNode
*
)
pNode
);
return
pRoot
;
}
}
static SQueryPlanNode* doCreateQueryPlanForSingleTableImpl(const SQueryStmtInfo* pQueryInfo, SQueryPlanNode* pNode, SQueryTableInfo* info) {
static
SLogicNode
*
createScanLogicNode
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
,
SRealTableNode
*
pRealTable
)
{
// group by column not by tag
SScanLogicNode
*
pScan
=
(
SScanLogicNode
*
)
nodesMakeNode
(
QUERY_NODE_LOGIC_PLAN_SCAN
);
size_t numOfGroupCols = taosArrayGetSize(pQueryInfo->groupbyExpr.columnInfo);
CHECK_ALLOC
(
pScan
,
NULL
);
pScan
->
node
.
id
=
pCxt
->
planNodeId
++
;
// check for aggregation
pScan
->
pMeta
=
pRealTable
->
pMeta
;
int32_t level = getExprFunctionLevel(pQueryInfo);
for(int32_t i = level - 1; i >= 0; --i) {
SArray* p = pQueryInfo->exprList[i];
size_t num = taosArrayGetSize(p);
bool aggregateFunc = false;
for(int32_t j = 0; j < num; ++j) {
SExprInfo* pExpr = (SExprInfo*)taosArrayGetP(p, 0);
if (pExpr->pExpr->nodeType != TEXPR_FUNCTION_NODE) {
continue;
}
aggregateFunc = qIsAggregateFunction(pExpr->pExpr->_function.functionName);
// set columns to scan
if (aggregateFunc) {
SNodeList
*
pCols
=
NULL
;
break;
CHECK_CODE
(
nodesCollectColumns
(
pSelect
,
SQL_CLAUSE_FROM
,
pRealTable
->
table
.
tableAlias
,
&
pCols
),
(
SLogicNode
*
)
pScan
);
}
if
(
NULL
!=
pCols
)
{
}
pScan
->
pScanCols
=
nodesCloneList
(
pCols
);
CHECK_ALLOC
(
pScan
->
pScanCols
,
(
SLogicNode
*
)
pScan
);
if (aggregateFunc) {
if (pQueryInfo->interval.interval > 0) {
pNode = createQueryNode(QNODE_TIMEWINDOW, "TimeWindowAgg", &pNode, 1, p->pData, num, &pQueryInfo->interval);
} else if (pQueryInfo->sessionWindow.gap > 0) {
pNode = createQueryNode(QNODE_SESSIONWINDOW, "SessionWindowAgg", &pNode, 1, p->pData, num, &pQueryInfo->sessionWindow);
} else if (pQueryInfo->stateWindow.col.info.colId > 0) {
pNode = createQueryNode(QNODE_STATEWINDOW, "StateWindowAgg", &pNode, 1, p->pData, num, &pQueryInfo->stateWindow);
} else if (numOfGroupCols != 0 && !pQueryInfo->groupbyExpr.groupbyTag) {
pNode = createQueryNode(QNODE_GROUPBY, "Groupby", &pNode, 1, p->pData, num, &pQueryInfo->groupbyExpr);
} else {
pNode = createQueryNode(QNODE_AGGREGATE, "Aggregate", &pNode, 1, p->pData, num, NULL);
}
} else {
// here we can push down the projection to tablescan operator.
pNode->numOfExpr = num;
taosArrayAddAll(pNode->pExpr, p);
}
}
}
if (pQueryInfo->havingFieldNum > 0) {
// set output
// int32_t numOfExpr = (int32_t)taosArrayGetSize(pQueryInfo->exprList1);
if
(
NULL
!=
pCols
)
{
// pNode = createQueryNode(QNODE_PROJECT, "Projection", &pNode, 1, pQueryInfo->exprList1->pData, numOfExpr, NULL);
pScan
->
node
.
pTargets
=
nodesCloneList
(
pCols
);
CHECK_ALLOC
(
pScan
->
node
.
pTargets
,
(
SLogicNode
*
)
pScan
);
}
}
if (pQueryInfo->fillType != TSDB_FILL_NONE) {
pScan
->
scanType
=
SCAN_TYPE_TABLE
;
SFillEssInfo* pInfo = calloc(1, sizeof(SFillEssInfo));
pScan
->
scanFlag
=
MAIN_SCAN
;
pInfo->fillType = pQueryInfo->fillType;
pScan
->
scanRange
=
TSWINDOW_INITIALIZER
;
pInfo->val = calloc(pNode->numOfExpr, sizeof(int64_t));
memcpy(pInfo->val, pQueryInfo->fillVal, pNode->numOfExpr);
SArray* p = pQueryInfo->exprList[0]; // top expression in select clause
pNode = createQueryNode(QNODE_FILL, "Fill", &pNode, 1, p->pData, taosArrayGetSize(p), pInfo);
}
if (pQueryInfo->order != NULL) {
return
(
SLogicNode
*
)
pScan
;
SArray* pList = pQueryInfo->exprList[0];
}
pNode = createQueryNode(QNODE_SORT, "Sort", &pNode, 1, pList->pData, taosArrayGetSize(pList), pQueryInfo->order);
}
if (pQueryInfo->limit.limit != -1 || pQueryInfo->limit.offset != 0) {
static
SLogicNode
*
createSubqueryLogicNode
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
,
STempTableNode
*
pTable
)
{
pNode = createQueryNode(QNODE_LIMIT, "Limit", &pNode, 1, NULL, 0, &pQueryInfo->limit);
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
;
return pNode;
}
}
static SQueryPlanNode* doCreateQueryPlanForSingleTable(const SQueryStmtInfo* pQueryInfo, STableMetaInfo* pTableMetaInfo, SArray* pExprs,
static
SLogicNode
*
createJoinLogicNode
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
,
SJoinTableNode
*
pJoinTable
)
{
SArray* tableCols) {
SJoinLogicNode
*
pJoin
=
(
SJoinLogicNode
*
)
nodesMakeNode
(
QUERY_NODE_LOGIC_PLAN_JOIN
);
char name[TSDB_TABLE_FNAME_LEN] = {0};
CHECK_ALLOC
(
pJoin
,
NULL
);
tstrncpy(name, pTableMetaInfo->name.tname, TSDB_TABLE_FNAME_LEN);
pJoin
->
node
.
id
=
pCxt
->
planNodeId
++
;
SQueryTableInfo info = {.tableName = strdup(name), .uid = pTableMetaInfo->pTableMeta->uid,};
pJoin
->
joinType
=
pJoinTable
->
joinType
;
info.window = pQueryInfo->window;
info.pMeta = pTableMetaInfo;
// set left and right node
pJoin
->
node
.
pChildren
=
nodesMakeList
();
// handle the only tag query
CHECK_ALLOC
(
pJoin
->
node
.
pChildren
,
(
SLogicNode
*
)
pJoin
);
SQueryPlanNode* pNode = doAddTableColumnNode(pQueryInfo, &info, pExprs, tableCols);
SLogicNode
*
pLeft
=
createLogicNodeByTable
(
pCxt
,
pSelect
,
pJoinTable
->
pLeft
);
if (pQueryInfo->info.onlyTagQuery) {
CHECK_ALLOC
(
pLeft
,
(
SLogicNode
*
)
pJoin
);
tfree(info.tableName);
CHECK_CODE
(
nodesListAppend
(
pJoin
->
node
.
pChildren
,
(
SNode
*
)
pLeft
),
(
SLogicNode
*
)
pJoin
);
return pNode;
SLogicNode
*
pRight
=
createLogicNodeByTable
(
pCxt
,
pSelect
,
pJoinTable
->
pRight
);
CHECK_ALLOC
(
pRight
,
(
SLogicNode
*
)
pJoin
);
CHECK_CODE
(
nodesListAppend
(
pJoin
->
node
.
pChildren
,
(
SNode
*
)
pRight
),
(
SLogicNode
*
)
pJoin
);
// set on conditions
if
(
NULL
!=
pJoinTable
->
pOnCond
)
{
pJoin
->
pOnConditions
=
nodesCloneNode
(
pJoinTable
->
pOnCond
);
CHECK_ALLOC
(
pJoin
->
pOnConditions
,
(
SLogicNode
*
)
pJoin
);
}
}
SQueryPlanNode* pNode1 = doCreateQueryPlanForSingleTableImpl(pQueryInfo, pNode, &info);
// set the output
tfree(info.tableName);
pJoin
->
node
.
pTargets
=
nodesCloneList
(
pLeft
->
pTargets
);
return pNode1;
CHECK_ALLOC
(
pJoin
->
node
.
pTargets
,
(
SLogicNode
*
)
pJoin
);
}
SNodeList
*
pTargets
=
nodesCloneList
(
pRight
->
pTargets
);
CHECK_ALLOC
(
pTargets
,
(
SLogicNode
*
)
pJoin
);
nodesListAppendList
(
pJoin
->
node
.
pTargets
,
pTargets
);
static bool isAllAggExpr(SArray* pList) {
return
(
SLogicNode
*
)
pJoin
;
assert(pList != NULL);
}
for (int32_t k = 0; k < taosArrayGetSize(pList); ++k) {
static
SLogicNode
*
createLogicNodeByTable
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
,
SNode
*
pTable
)
{
SExprInfo* p = taosArrayGetP(pList, k);
switch
(
nodeType
(
pTable
))
{
if (p->pExpr->nodeType != TEXPR_FUNCTION_NODE || !qIsAggregateFunction(p->pExpr->_function.functionName)) {
case
QUERY_NODE_REAL_TABLE
:
return false;
return
createScanLogicNode
(
pCxt
,
pSelect
,
(
SRealTableNode
*
)
pTable
);
}
case
QUERY_NODE_TEMP_TABLE
:
return
createSubqueryLogicNode
(
pCxt
,
pSelect
,
(
STempTableNode
*
)
pTable
);
case
QUERY_NODE_JOIN_TABLE
:
return
createJoinLogicNode
(
pCxt
,
pSelect
,
(
SJoinTableNode
*
)
pTable
);
default:
break
;
}
}
return
NULL
;
return true;
}
}
SArray* createQueryPlanImpl(const SQueryStmtInfo* pQueryInfo) {
typedef
struct
SCreateColumnCxt
{
SArray* pDownstream = NULL;
int32_t
errCode
;
SNodeList
*
pList
;
if (pQueryInfo->pDownstream != NULL && taosArrayGetSize(pQueryInfo->pDownstream) > 0) { // subquery in the from clause
}
SCreateColumnCxt
;
pDownstream = taosArrayInit(4, POINTER_BYTES);
static
EDealRes
doCreateColumn
(
SNode
*
pNode
,
void
*
pContext
)
{
size_t size = taosArrayGetSize(pQueryInfo->pDownstream);
SCreateColumnCxt
*
pCxt
=
(
SCreateColumnCxt
*
)
pContext
;
for(int32_t i = 0; i < size; ++i) {
switch
(
nodeType
(
pNode
))
{
SQueryStmtInfo* pq = taosArrayGet(pQueryInfo->pDownstream, i);
case
QUERY_NODE_COLUMN
:
{
SArray* p = createQueryPlanImpl(pq);
SNode
*
pCol
=
nodesCloneNode
(
pNode
);
taosArrayAddBatch(pDownstream, p->pData, (int32_t) taosArrayGetSize(p));
CHECK_ALLOC
(
pCol
,
DEAL_RES_ERROR
);
CHECK_CODE
(
nodesListAppend
(
pCxt
->
pList
,
pCol
),
DEAL_RES_ERROR
);
return
DEAL_RES_IGNORE_CHILD
;
}
}
}
case
QUERY_NODE_OPERATOR
:
case
QUERY_NODE_LOGIC_CONDITION
:
if (pQueryInfo->numOfTables > 1) { // it is a join query
case
QUERY_NODE_FUNCTION
:
{
// 1. separate the select clause according to table
SExprNode
*
pExpr
=
(
SExprNode
*
)
pNode
;
taosArrayDestroy(pDownstream);
SColumnNode
*
pCol
=
(
SColumnNode
*
)
nodesMakeNode
(
QUERY_NODE_COLUMN
);
pDownstream = taosArrayInit(5, POINTER_BYTES);
CHECK_ALLOC
(
pCol
,
DEAL_RES_ERROR
);
pCol
->
node
.
resType
=
pExpr
->
resType
;
for(int32_t i = 0; i < pQueryInfo->numOfTables; ++i) {
strcpy
(
pCol
->
colName
,
pExpr
->
aliasName
);
STableMetaInfo* pTableMetaInfo = pQueryInfo->pTableMetaInfo[i];
CHECK_CODE
(
nodesListAppend
(
pCxt
->
pList
,
(
SNode
*
)
pCol
),
DEAL_RES_ERROR
);
uint64_t uid = pTableMetaInfo->pTableMeta->uid;
return
DEAL_RES_IGNORE_CHILD
;
SArray* exprList = taosArrayInit(4, POINTER_BYTES);
if (copyExprInfoList(exprList, pQueryInfo->exprList[0], uid, true) != 0) {
terrno = TSDB_CODE_TSC_OUT_OF_MEMORY;
exit(-1);
}
// 2. create the query execution node
char name[TSDB_TABLE_FNAME_LEN] = {0};
tNameExtractFullName(&pTableMetaInfo->name, name);
SQueryTableInfo info = {.tableName = strdup(name), .uid = pTableMetaInfo->pTableMeta->uid,};
// 3. get the required table column list
SArray* tableColumnList = taosArrayInit(4, sizeof(SColumn));
columnListCopy(tableColumnList, pQueryInfo->colList, uid);
// 4. add the projection query node
SQueryPlanNode* pNode = doAddTableColumnNode(pQueryInfo, &info, exprList, tableColumnList);
columnListDestroy(tableColumnList);
taosArrayPush(pDownstream, &pNode);
}
}
default:
// 3. add the join node here
break
;
SQueryTableInfo info = {0};
int32_t num = (int32_t) taosArrayGetSize(pQueryInfo->exprList[0]);
SQueryPlanNode* pNode = createQueryNode(QNODE_JOIN, "Join", pDownstream->pData, pQueryInfo->numOfTables,
pQueryInfo->exprList[0]->pData, num, NULL);
// 4. add the aggregation or projection execution node
pNode = doCreateQueryPlanForSingleTableImpl(pQueryInfo, pNode, &info);
pDownstream = taosArrayInit(5, POINTER_BYTES);
taosArrayPush(pDownstream, &pNode);
} else { // only one table, normal query process
STableMetaInfo* pTableMetaInfo = pQueryInfo->pTableMetaInfo[0];
SQueryPlanNode* pNode = doCreateQueryPlanForSingleTable(pQueryInfo, pTableMetaInfo, pQueryInfo->exprList[0], pQueryInfo->colList);
pDownstream = taosArrayInit(5, POINTER_BYTES);
taosArrayPush(pDownstream, &pNode);
}
}
return
pDownstream
;
return
DEAL_RES_CONTINUE
;
}
}
static void doDestroyQueryNode(SQueryPlanNode* pQueryNode) {
static
SNodeList
*
createColumnByRewriteExps
(
SLogicPlanContext
*
pCxt
,
SNodeList
*
pExprs
)
{
int32_t type = queryNodeType(pQueryNode);
SCreateColumnCxt
cxt
=
{
.
errCode
=
TSDB_CODE_SUCCESS
,
.
pList
=
nodesMakeList
()
};
if (type == QNODE_MODIFY) {
CHECK_ALLOC
(
cxt
.
pList
,
NULL
);
SDataPayloadInfo* pInfo = pQueryNode->pExtInfo;
size_t size = taosArrayGetSize(pInfo->payload);
for (int32_t i = 0; i < size; ++i) {
SVgDataBlocks* pBlock = taosArrayGetP(pInfo->payload, i);
tfree(pBlock);
}
taosArrayDestroy(pInfo->payload);
nodesWalkList
(
pExprs
,
doCreateColumn
,
&
cxt
);
if
(
TSDB_CODE_SUCCESS
!=
cxt
.
errCode
)
{
nodesDestroyList
(
cxt
.
pList
);
return
NULL
;
}
}
return
cxt
.
pList
;
}
if (type == QNODE_STREAMSCAN || type == QNODE_TABLESCAN) {
static
SLogicNode
*
createAggLogicNode
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
)
{
SQueryTableInfo* pQueryTableInfo = pQueryNode->pExtInfo;
SNodeList
*
pAggFuncs
=
NULL
;
tfree(pQueryTableInfo->tableName);
CHECK_CODE
(
nodesCollectFuncs
(
pSelect
,
fmIsAggFunc
,
&
pAggFuncs
),
NULL
);
if
(
NULL
==
pAggFuncs
&&
NULL
==
pSelect
->
pGroupByList
)
{
return
NULL
;
}
}
taosArrayDestroy(pQueryNode->pExpr);
SAggLogicNode
*
pAgg
=
(
SAggLogicNode
*
)
nodesMakeNode
(
QUERY_NODE_LOGIC_PLAN_AGG
);
CHECK_ALLOC
(
pAgg
,
NULL
);
tfree(pQueryNode->pExtInfo);
pAgg
->
node
.
id
=
pCxt
->
planNodeId
++
;
tfree(pQueryNode->pSchema);
tfree(pQueryNode->info.name);
if (pQueryNode->pChildren != NULL) {
// set grouyp keys, agg funcs and having conditions
int32_t size = (int32_t) taosArrayGetSize(pQueryNode->pChildren);
if
(
NULL
!=
pSelect
->
pGroupByList
)
{
for(int32_t i = 0; i < size; ++i) {
pAgg
->
pGroupKeys
=
nodesCloneList
(
pSelect
->
pGroupByList
);
SQueryPlanNode* p = taosArrayGetP(pQueryNode->pChildren, i);
CHECK_ALLOC
(
pAgg
->
pGroupKeys
,
(
SLogicNode
*
)
pAgg
);
doDestroyQueryNode(p);
}
taosArrayDestroy(pQueryNode->pChildren);
}
}
if
(
NULL
!=
pAggFuncs
)
{
tfree(pQueryNode);
pAgg
->
pAggFuncs
=
nodesCloneList
(
pAggFuncs
);
}
CHECK_ALLOC
(
pAgg
->
pAggFuncs
,
(
SLogicNode
*
)
pAgg
);
static int32_t doPrintPlan(char* buf, SQueryPlanNode* pQueryNode, int32_t level, int32_t totalLen) {
if (level > 0) {
sprintf(buf + totalLen, "%*c", level, ' ');
totalLen += level;
}
}
int32_t len1 = sprintf(buf + totalLen, "%s(", pQueryNode->info.name);
// rewrite the expression in subsequent clauses
int32_t len = len1 + totalLen;
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
);
switch(pQueryNode->info.type) {
case QNODE_STREAMSCAN:
case QNODE_TABLESCAN: {
SQueryTableInfo* pInfo = (SQueryTableInfo*)pQueryNode->pExtInfo;
len1 = sprintf(buf + len, "%s #%" PRIu64, pInfo->tableName, pInfo->uid);
assert(len1 > 0);
len += len1;
len1 = sprintf(buf + len, " , cols:");
assert(len1 > 0);
len += len1;
len = printExprInfo(buf, pQueryNode, len);
len1 = sprintf(buf + len, ")");
assert(len1 > 0);
// todo print filter info
len1 = sprintf(buf + len, ") filters:(nil)");
len += len1;
len1 = sprintf(buf + len, " time_range: %" PRId64 " - %" PRId64"\n", pInfo->window.skey, pInfo->window.ekey);
len += len1;
break;
}
case QNODE_PROJECT: {
len1 = sprintf(buf + len, "cols:");
assert(len1 > 0);
len += len1;
len = printExprInfo(buf, pQueryNode, len);
if
(
NULL
!=
pSelect
->
pHaving
)
{
len1 = sprintf(buf + len, ")");
pAgg
->
node
.
pConditions
=
nodesCloneNode
(
pSelect
->
pHaving
);
len += len1;
CHECK_ALLOC
(
pAgg
->
node
.
pConditions
,
(
SLogicNode
*
)
pAgg
);
}
// todo print filter info
len1 = sprintf(buf + len, " filters:(nil)\n");
len += len1;
break;
}
case QNODE_AGGREGATE: {
len = printExprInfo(buf, pQueryNode, len);
len1 = sprintf(buf + len, ")\n");
len += len1;
break;
}
case QNODE_TIMEWINDOW: {
len = printExprInfo(buf, pQueryNode, len);
len1 = sprintf(buf + len, ") ");
len += len1;
SInterval* pInterval = pQueryNode->pExtInfo;
// todo dynamic return the time precision
len1 = sprintf(buf + len, "interval:%" PRId64 "(%s), sliding:%" PRId64 "(%s), offset:%" PRId64 "(%s)\n",
pInterval->interval, TSDB_TIME_PRECISION_MILLI_STR, pInterval->sliding,
TSDB_TIME_PRECISION_MILLI_STR, pInterval->offset, TSDB_TIME_PRECISION_MILLI_STR);
len += len1;
break;
}
case QNODE_STATEWINDOW: {
len = printExprInfo(buf, pQueryNode, len);
len1 = sprintf(buf + len, ") ");
len += len1;
SColumn* pCol = pQueryNode->pExtInfo;
len1 = sprintf(buf + len, "col:%s #%d\n", pCol->name, pCol->info.colId);
len += len1;
break;
}
case QNODE_SESSIONWINDOW: {
len = printExprInfo(buf, pQueryNode, len);
len1 = sprintf(buf + len, ") ");
len += len1;
struct SSessionWindow* ps = pQueryNode->pExtInfo;
len1 = sprintf(buf + len, "col:[%s #%d], gap:%" PRId64 " (ms) \n", ps->col.name, ps->col.info.colId, ps->gap);
len += len1;
break;
}
case QNODE_GROUPBY: {
len = printExprInfo(buf, pQueryNode, len);
SGroupbyExpr* pGroupbyExpr = pQueryNode->pExtInfo;
len1 = sprintf(buf + len, ") groupby_col: ");
len += len1;
for (int32_t i = 0; i < taosArrayGetSize(pGroupbyExpr->columnInfo); ++i) {
SColumn* pCol = taosArrayGet(pGroupbyExpr->columnInfo, i);
len1 = sprintf(buf + len, "[%s #%d] ", pCol->name, pCol->info.colId);
len += len1;
}
len += sprintf(buf + len, "\n");
break;
}
case QNODE_FILL: {
SFillEssInfo* pEssInfo = pQueryNode->pExtInfo;
len1 = sprintf(buf + len, "%d", pEssInfo->fillType);
len += len1;
if (pEssInfo->fillType == TSDB_FILL_SET_VALUE) {
len1 = sprintf(buf + len, ", val:");
len += len1;
// todo get the correct fill data type
for (int32_t i = 0; i < pQueryNode->numOfExpr; ++i) {
len1 = sprintf(buf + len, "%" PRId64, pEssInfo->val[i]);
len += len1;
if (i < pQueryNode->numOfExpr - 1) {
len1 = sprintf(buf + len, ", ");
len += len1;
}
}
}
len1 = sprintf(buf + len, ")\n");
len += len1;
break;
}
case QNODE_LIMIT: {
SLimit* pVal = pQueryNode->pExtInfo;
len1 = sprintf(buf + len, "limit: %" PRId64 ", offset: %" PRId64 ")\n", pVal->limit, pVal->offset);
len += len1;
break;
}
case QNODE_DISTINCT:
case QNODE_TAGSCAN: {
len1 = sprintf(buf + len, "cols: ");
len += len1;
len = printExprInfo(buf, pQueryNode, len);
len1 = sprintf(buf + len, ")\n");
len += len1;
break;
}
case QNODE_SORT: {
len1 = sprintf(buf + len, "cols:");
len += len1;
SArray* pSort = pQueryNode->pExtInfo;
for (int32_t i = 0; i < taosArrayGetSize(pSort); ++i) {
SOrder* p = taosArrayGet(pSort, i);
len1 = sprintf(buf + len, " [%s #%d %s]", p->col.name, p->col.info.colId, p->order == TSDB_ORDER_ASC? "ASC":"DESC");
len += len1;
// set the output
}
pAgg
->
node
.
pTargets
=
nodesMakeList
();
CHECK_ALLOC
(
pAgg
->
node
.
pTargets
,
(
SLogicNode
*
)
pAgg
);
if
(
NULL
!=
pAgg
->
pGroupKeys
)
{
SNodeList
*
pTargets
=
createColumnByRewriteExps
(
pCxt
,
pAgg
->
pGroupKeys
);
CHECK_ALLOC
(
pAgg
->
node
.
pTargets
,
(
SLogicNode
*
)
pAgg
);
nodesListAppendList
(
pAgg
->
node
.
pTargets
,
pTargets
);
}
if
(
NULL
!=
pAgg
->
pAggFuncs
)
{
SNodeList
*
pTargets
=
createColumnByRewriteExps
(
pCxt
,
pAgg
->
pAggFuncs
);
CHECK_ALLOC
(
pTargets
,
(
SLogicNode
*
)
pAgg
);
nodesListAppendList
(
pAgg
->
node
.
pTargets
,
pTargets
);
}
return
(
SLogicNode
*
)
pAgg
;
}
len1 = sprintf(buf + len, ")\n");
static
SNodeList
*
createColumnByProjections
(
SLogicPlanContext
*
pCxt
,
SNodeList
*
pExprs
)
{
len += len1;
SNodeList
*
pList
=
nodesMakeList
();
break;
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
;
case QNODE_JOIN: {
strcpy
(
pCol
->
colName
,
pExpr
->
aliasName
);
// print join condition
if
(
TSDB_CODE_SUCCESS
!=
nodesListAppend
(
pList
,
(
SNode
*
)
pCol
))
{
len1 = sprintf(buf + len, ")\n");
goto
error
;
len += len1;
break;
}
}
}
}
return
pList
;
return len;
error:
nodesDestroyList
(
pList
);
return
NULL
;
}
}
int32_t printExprInfo(char* buf, const SQueryPlanNode* pQueryNode, int32_t len) {
static
SLogicNode
*
createProjectLogicNode
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
)
{
int32_t len1 = 0;
SProjectLogicNode
*
pProject
=
(
SProjectLogicNode
*
)
nodesMakeNode
(
QUERY_NODE_LOGIC_PLAN_PROJECT
);
CHECK_ALLOC
(
pProject
,
NULL
);
for (int32_t i = 0; i < pQueryNode->numOfExpr; ++i) {
pProject
->
node
.
id
=
pCxt
->
planNodeId
++
;
SExprInfo* pExprInfo = taosArrayGetP(pQueryNode->pExpr, i);
SSqlExpr* pExpr = &pExprInfo->base;
pProject
->
pProjections
=
nodesCloneList
(
pSelect
->
pProjectionList
);
len1 = sprintf(buf + len, "%s [%s #%d]", pExpr->token, pExpr->resSchema.name, pExpr->resSchema.colId);
assert(len1 > 0);
len += len1;
pProject
->
node
.
pTargets
=
createColumnByProjections
(
pCxt
,
pSelect
->
pProjectionList
);
if (i < pQueryNode->numOfExpr - 1) {
CHECK_ALLOC
(
pProject
->
node
.
pTargets
,
(
SLogicNode
*
)
pProject
);
len1 = sprintf(buf + len, ", ");
len += len1;
}
}
return
len
;
return
(
SLogicNode
*
)
pProject
;
}
}
int32_t queryPlanToStringImpl(char* buf, SQueryPlanNode* pQueryNode, int32_t level, int32_t totalLen) {
static
SLogicNode
*
createSelectLogicNode
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
)
{
int32_t len = doPrintPlan(buf, pQueryNode, level, totalLen);
SLogicNode
*
pRoot
=
createLogicNodeByTable
(
pCxt
,
pSelect
,
pSelect
->
pFromTable
);
if
(
TSDB_CODE_SUCCESS
==
pCxt
->
errCode
&&
NULL
!=
pSelect
->
pWhere
)
{
for(int32_t i = 0; i < taosArrayGetSize(pQueryNode->pChildren); ++i) {
pRoot
->
pConditions
=
nodesCloneNode
(
pSelect
->
pWhere
);
SQueryPlanNode* p1 = taosArrayGetP(pQueryNode->pChildren, i);
CHECK_ALLOC
(
pRoot
->
pConditions
,
pRoot
);
int32_t len1 = queryPlanToStringImpl(buf, p1, level + 1, len);
len = len1;
}
}
if
(
TSDB_CODE_SUCCESS
==
pCxt
->
errCode
)
{
return len;
pRoot
=
pushLogicNode
(
pCxt
,
pRoot
,
createAggLogicNode
(
pCxt
,
pSelect
));
}
if
(
TSDB_CODE_SUCCESS
==
pCxt
->
errCode
)
{
pRoot
=
pushLogicNode
(
pCxt
,
pRoot
,
createProjectLogicNode
(
pCxt
,
pSelect
));
}
return
pRoot
;
}
}
int32_t queryPlanToString(struct SQueryPlanNode* pQueryNode, char** str) {
static
SLogicNode
*
createQueryLogicNode
(
SLogicPlanContext
*
pCxt
,
SNode
*
pStmt
)
{
assert(pQueryNode);
switch
(
nodeType
(
pStmt
))
{
*str = calloc(1, 4096);
case
QUERY_NODE_SELECT_STMT
:
return
createSelectLogicNode
(
pCxt
,
(
SSelectStmt
*
)
pStmt
);
int32_t len = sprintf(*str, "===== logic plan =====\n");
default:
queryPlanToStringImpl(*str, pQueryNode, 0, len);
break
;
}
return TSDB_CODE_SUCCESS;
}
}
SQueryPlanNode* queryPlanFromString() {
int32_t
createLogicPlan
(
SPlanContext
*
pCxt
,
SLogicNode
**
pLogicNode
)
{
return NULL;
SLogicPlanContext
cxt
=
{
.
errCode
=
TSDB_CODE_SUCCESS
,
.
planNodeId
=
1
};
SLogicNode
*
pRoot
=
createQueryLogicNode
(
&
cxt
,
pCxt
->
pAstRoot
);
if
(
TSDB_CODE_SUCCESS
!=
cxt
.
errCode
)
{
nodesDestroyNode
((
SNode
*
)
pRoot
);
return
cxt
.
errCode
;
}
*
pLogicNode
=
pRoot
;
return
TSDB_CODE_SUCCESS
;
}
}
#endif
source/libs/planner/src/physicalPlan.c
浏览文件 @
cd7a0e55
...
@@ -492,3 +492,483 @@ void qDestroySubplan(SSubplan* pSubplan) {
...
@@ -492,3 +492,483 @@ void qDestroySubplan(SSubplan* pSubplan) {
}
}
#endif
#endif
#include "plannerInt.h"
#include "functionMgt.h"
typedef
struct
SSubLogicPlan
{
SNode
*
pRoot
;
// SLogicNode
bool
haveSuperTable
;
bool
haveSystemTable
;
}
SSubLogicPlan
;
int32_t
splitLogicPlan
(
SSubLogicPlan
*
pLogicPlan
)
{
// todo
return
TSDB_CODE_SUCCESS
;
}
typedef
struct
SSlotIndex
{
int16_t
dataBlockId
;
int16_t
slotId
;
}
SSlotIndex
;
typedef
struct
SPhysiPlanContext
{
int32_t
errCode
;
int16_t
nextDataBlockId
;
SArray
*
pLocationHelper
;
}
SPhysiPlanContext
;
static
int32_t
getSlotKey
(
SNode
*
pNode
,
char
*
pKey
)
{
if
(
QUERY_NODE_COLUMN
==
nodeType
(
pNode
))
{
SColumnNode
*
pCol
=
(
SColumnNode
*
)
pNode
;
if
(
'\0'
==
pCol
->
tableAlias
[
0
])
{
return
sprintf
(
pKey
,
"%s"
,
pCol
->
colName
);
}
return
sprintf
(
pKey
,
"%s.%s"
,
pCol
->
tableAlias
,
pCol
->
colName
);
}
return
sprintf
(
pKey
,
"%s"
,
((
SExprNode
*
)
pNode
)
->
aliasName
);
}
static
SNode
*
createSlotDesc
(
SPhysiPlanContext
*
pCxt
,
const
SNode
*
pNode
,
int16_t
slotId
)
{
SSlotDescNode
*
pSlot
=
(
SSlotDescNode
*
)
nodesMakeNode
(
QUERY_NODE_SLOT_DESC
);
CHECK_ALLOC
(
pSlot
,
NULL
);
pSlot
->
slotId
=
slotId
;
pSlot
->
dataType
=
((
SExprNode
*
)
pNode
)
->
resType
;
pSlot
->
reserve
=
false
;
pSlot
->
output
=
false
;
return
(
SNode
*
)
pSlot
;
}
static
SNode
*
createTarget
(
SNode
*
pNode
,
int16_t
dataBlockId
,
int16_t
slotId
)
{
STargetNode
*
pTarget
=
(
STargetNode
*
)
nodesMakeNode
(
QUERY_NODE_TARGET
);
if
(
NULL
==
pTarget
)
{
return
NULL
;
}
pTarget
->
dataBlockId
=
dataBlockId
;
pTarget
->
slotId
=
slotId
;
pTarget
->
pExpr
=
pNode
;
return
(
SNode
*
)
pTarget
;
}
static
int32_t
addDataBlockDesc
(
SPhysiPlanContext
*
pCxt
,
SNodeList
*
pList
,
SDataBlockDescNode
*
pDataBlockDesc
)
{
SHashObj
*
pHash
=
NULL
;
if
(
NULL
==
pDataBlockDesc
->
pSlots
)
{
pDataBlockDesc
->
pSlots
=
nodesMakeList
();
CHECK_ALLOC
(
pDataBlockDesc
->
pSlots
,
TSDB_CODE_OUT_OF_MEMORY
);
pHash
=
taosHashInit
(
LIST_LENGTH
(
pList
),
taosGetDefaultHashFunction
(
TSDB_DATA_TYPE_BINARY
),
true
,
HASH_NO_LOCK
);
CHECK_ALLOC
(
pHash
,
TSDB_CODE_OUT_OF_MEMORY
);
if
(
NULL
==
taosArrayInsert
(
pCxt
->
pLocationHelper
,
pDataBlockDesc
->
dataBlockId
,
&
pHash
))
{
taosHashCleanup
(
pHash
);
return
TSDB_CODE_OUT_OF_MEMORY
;
}
}
else
{
pHash
=
taosArrayGetP
(
pCxt
->
pLocationHelper
,
pDataBlockDesc
->
dataBlockId
);
}
SNode
*
pNode
=
NULL
;
int16_t
slotId
=
taosHashGetSize
(
pHash
);
FOREACH
(
pNode
,
pList
)
{
SNode
*
pSlot
=
createSlotDesc
(
pCxt
,
pNode
,
slotId
);
CHECK_ALLOC
(
pSlot
,
TSDB_CODE_OUT_OF_MEMORY
);
if
(
TSDB_CODE_SUCCESS
!=
nodesListAppend
(
pDataBlockDesc
->
pSlots
,
(
SNode
*
)
pSlot
))
{
nodesDestroyNode
(
pSlot
);
return
TSDB_CODE_OUT_OF_MEMORY
;
}
SSlotIndex
index
=
{
.
dataBlockId
=
pDataBlockDesc
->
dataBlockId
,
.
slotId
=
slotId
};
char
name
[
TSDB_TABLE_NAME_LEN
+
TSDB_COL_NAME_LEN
];
int32_t
len
=
getSlotKey
(
pNode
,
name
);
CHECK_CODE
(
taosHashPut
(
pHash
,
name
,
len
,
&
index
,
sizeof
(
SSlotIndex
)),
TSDB_CODE_OUT_OF_MEMORY
);
SNode
*
pTarget
=
createTarget
(
pNode
,
pDataBlockDesc
->
dataBlockId
,
slotId
);
CHECK_ALLOC
(
pTarget
,
TSDB_CODE_OUT_OF_MEMORY
);
REPLACE_NODE
(
pTarget
);
++
slotId
;
}
return
TSDB_CODE_SUCCESS
;
}
typedef
struct
SSetSlotIdCxt
{
int32_t
errCode
;
SHashObj
*
pLeftHash
;
SHashObj
*
pRightHash
;
}
SSetSlotIdCxt
;
static
EDealRes
doSetSlotId
(
SNode
*
pNode
,
void
*
pContext
)
{
if
(
QUERY_NODE_COLUMN
==
nodeType
(
pNode
)
&&
0
!=
strcmp
(((
SColumnNode
*
)
pNode
)
->
colName
,
"*"
))
{
SSetSlotIdCxt
*
pCxt
=
(
SSetSlotIdCxt
*
)
pContext
;
char
name
[
TSDB_TABLE_NAME_LEN
+
TSDB_COL_NAME_LEN
];
int32_t
len
=
getSlotKey
(
pNode
,
name
);
SSlotIndex
*
pIndex
=
taosHashGet
(
pCxt
->
pLeftHash
,
name
,
len
);
if
(
NULL
==
pIndex
)
{
pIndex
=
taosHashGet
(
pCxt
->
pRightHash
,
name
,
len
);
}
// pIndex is definitely not NULL, otherwise it is a bug
((
SColumnNode
*
)
pNode
)
->
dataBlockId
=
pIndex
->
dataBlockId
;
((
SColumnNode
*
)
pNode
)
->
slotId
=
pIndex
->
slotId
;
CHECK_ALLOC
(
pNode
,
DEAL_RES_ERROR
);
return
DEAL_RES_IGNORE_CHILD
;
}
return
DEAL_RES_CONTINUE
;
}
static
SNode
*
setNodeSlotId
(
SPhysiPlanContext
*
pCxt
,
int16_t
leftDataBlockId
,
int16_t
rightDataBlockId
,
SNode
*
pNode
)
{
SNode
*
pRes
=
nodesCloneNode
(
pNode
);
CHECK_ALLOC
(
pRes
,
NULL
);
SSetSlotIdCxt
cxt
=
{
.
errCode
=
TSDB_CODE_SUCCESS
,
.
pLeftHash
=
taosArrayGetP
(
pCxt
->
pLocationHelper
,
leftDataBlockId
),
.
pRightHash
=
(
rightDataBlockId
<
0
?
NULL
:
taosArrayGetP
(
pCxt
->
pLocationHelper
,
rightDataBlockId
))
};
nodesWalkNode
(
pRes
,
doSetSlotId
,
&
cxt
);
if
(
TSDB_CODE_SUCCESS
!=
cxt
.
errCode
)
{
nodesDestroyNode
(
pRes
);
return
NULL
;
}
return
pRes
;
}
static
SNodeList
*
setListSlotId
(
SPhysiPlanContext
*
pCxt
,
int16_t
leftDataBlockId
,
int16_t
rightDataBlockId
,
SNodeList
*
pList
)
{
SNodeList
*
pRes
=
nodesCloneList
(
pList
);
CHECK_ALLOC
(
pRes
,
NULL
);
SSetSlotIdCxt
cxt
=
{
.
errCode
=
TSDB_CODE_SUCCESS
,
.
pLeftHash
=
taosArrayGetP
(
pCxt
->
pLocationHelper
,
leftDataBlockId
),
.
pRightHash
=
(
rightDataBlockId
<
0
?
NULL
:
taosArrayGetP
(
pCxt
->
pLocationHelper
,
rightDataBlockId
))
};
nodesWalkList
(
pRes
,
doSetSlotId
,
&
cxt
);
if
(
TSDB_CODE_SUCCESS
!=
cxt
.
errCode
)
{
nodesDestroyList
(
pRes
);
return
NULL
;
}
return
pRes
;
}
static
SPhysiNode
*
makePhysiNode
(
SPhysiPlanContext
*
pCxt
,
ENodeType
type
)
{
SPhysiNode
*
pPhysiNode
=
(
SPhysiNode
*
)
nodesMakeNode
(
type
);
if
(
NULL
==
pPhysiNode
)
{
return
NULL
;
}
pPhysiNode
->
outputDataBlockDesc
.
dataBlockId
=
pCxt
->
nextDataBlockId
++
;
pPhysiNode
->
outputDataBlockDesc
.
type
=
QUERY_NODE_DATABLOCK_DESC
;
return
pPhysiNode
;
}
static
int32_t
setConditionsSlotId
(
SPhysiPlanContext
*
pCxt
,
const
SLogicNode
*
pLogicNode
,
SPhysiNode
*
pPhysiNode
)
{
if
(
NULL
!=
pLogicNode
->
pConditions
)
{
pPhysiNode
->
pConditions
=
setNodeSlotId
(
pCxt
,
pPhysiNode
->
outputDataBlockDesc
.
dataBlockId
,
-
1
,
pLogicNode
->
pConditions
);
CHECK_ALLOC
(
pPhysiNode
->
pConditions
,
TSDB_CODE_OUT_OF_MEMORY
);
}
return
TSDB_CODE_SUCCESS
;
}
static
int32_t
setSlotOutput
(
SPhysiPlanContext
*
pCxt
,
SNodeList
*
pTargets
,
SDataBlockDescNode
*
pDataBlockDesc
)
{
SHashObj
*
pHash
=
taosArrayGetP
(
pCxt
->
pLocationHelper
,
pDataBlockDesc
->
dataBlockId
);
char
name
[
TSDB_TABLE_NAME_LEN
+
TSDB_COL_NAME_LEN
];
SNode
*
pNode
;
FOREACH
(
pNode
,
pTargets
)
{
int32_t
len
=
getSlotKey
(
pNode
,
name
);
SSlotIndex
*
pIndex
=
taosHashGet
(
pHash
,
name
,
len
);
((
SSlotDescNode
*
)
nodesListGetNode
(
pDataBlockDesc
->
pSlots
,
pIndex
->
slotId
))
->
output
=
true
;
}
return
TSDB_CODE_SUCCESS
;
}
static
int32_t
initScanPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SScanLogicNode
*
pScanLogicNode
,
SScanPhysiNode
*
pScanPhysiNode
)
{
if
(
NULL
!=
pScanLogicNode
->
pScanCols
)
{
pScanPhysiNode
->
pScanCols
=
nodesCloneList
(
pScanLogicNode
->
pScanCols
);
CHECK_ALLOC
(
pScanPhysiNode
->
pScanCols
,
TSDB_CODE_OUT_OF_MEMORY
);
}
// Data block describe also needs to be set without scanning column, such as SELECT COUNT(*) FROM t
CHECK_CODE
(
addDataBlockDesc
(
pCxt
,
pScanPhysiNode
->
pScanCols
,
&
pScanPhysiNode
->
node
.
outputDataBlockDesc
),
TSDB_CODE_OUT_OF_MEMORY
);
CHECK_CODE
(
setConditionsSlotId
(
pCxt
,
(
const
SLogicNode
*
)
pScanLogicNode
,
(
SPhysiNode
*
)
pScanPhysiNode
),
TSDB_CODE_OUT_OF_MEMORY
);
CHECK_CODE
(
setSlotOutput
(
pCxt
,
pScanLogicNode
->
node
.
pTargets
,
&
pScanPhysiNode
->
node
.
outputDataBlockDesc
),
TSDB_CODE_OUT_OF_MEMORY
);
pScanPhysiNode
->
uid
=
pScanLogicNode
->
pMeta
->
uid
;
pScanPhysiNode
->
tableType
=
pScanLogicNode
->
pMeta
->
tableType
;
pScanPhysiNode
->
order
=
TSDB_ORDER_ASC
;
pScanPhysiNode
->
count
=
1
;
pScanPhysiNode
->
reverse
=
0
;
return
TSDB_CODE_SUCCESS
;
}
static
SPhysiNode
*
createTagScanPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SScanLogicNode
*
pScanLogicNode
)
{
STagScanPhysiNode
*
pTagScan
=
(
STagScanPhysiNode
*
)
makePhysiNode
(
pCxt
,
QUERY_NODE_PHYSICAL_PLAN_TAG_SCAN
);
CHECK_ALLOC
(
pTagScan
,
NULL
);
CHECK_CODE
(
initScanPhysiNode
(
pCxt
,
pScanLogicNode
,
(
SScanPhysiNode
*
)
pTagScan
),
(
SPhysiNode
*
)
pTagScan
);
return
(
SPhysiNode
*
)
pTagScan
;
}
static
SPhysiNode
*
createTableScanPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SScanLogicNode
*
pScanLogicNode
)
{
STableScanPhysiNode
*
pTableScan
=
(
STableScanPhysiNode
*
)
makePhysiNode
(
pCxt
,
QUERY_NODE_PHYSICAL_PLAN_TABLE_SCAN
);
CHECK_ALLOC
(
pTableScan
,
NULL
);
CHECK_CODE
(
initScanPhysiNode
(
pCxt
,
pScanLogicNode
,
(
SScanPhysiNode
*
)
pTableScan
),
(
SPhysiNode
*
)
pTableScan
);
pTableScan
->
scanFlag
=
pScanLogicNode
->
scanFlag
;
pTableScan
->
scanRange
=
pScanLogicNode
->
scanRange
;
return
(
SPhysiNode
*
)
pTableScan
;
}
static
SPhysiNode
*
createScanPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SScanLogicNode
*
pScanLogicNode
)
{
switch
(
pScanLogicNode
->
scanType
)
{
case
SCAN_TYPE_TAG
:
return
createTagScanPhysiNode
(
pCxt
,
pScanLogicNode
);
case
SCAN_TYPE_TABLE
:
return
createTableScanPhysiNode
(
pCxt
,
pScanLogicNode
);
case
SCAN_TYPE_STABLE
:
case
SCAN_TYPE_STREAM
:
break
;
default:
break
;
}
return
NULL
;
}
static
SNodeList
*
createJoinOutputCols
(
SPhysiPlanContext
*
pCxt
,
SDataBlockDescNode
*
pLeftDesc
,
SDataBlockDescNode
*
pRightDesc
)
{
SNodeList
*
pCols
=
nodesMakeList
();
CHECK_ALLOC
(
pCols
,
NULL
);
SNode
*
pNode
;
FOREACH
(
pNode
,
pLeftDesc
->
pSlots
)
{
SSlotDescNode
*
pSlot
=
(
SSlotDescNode
*
)
pNode
;
SColumnNode
*
pCol
=
(
SColumnNode
*
)
nodesMakeNode
(
QUERY_NODE_COLUMN
);
if
(
NULL
==
pCol
)
{
goto
error
;
}
pCol
->
node
.
resType
=
pSlot
->
dataType
;
pCol
->
dataBlockId
=
pLeftDesc
->
dataBlockId
;
pCol
->
slotId
=
pSlot
->
slotId
;
pCol
->
colId
=
-
1
;
if
(
TSDB_CODE_SUCCESS
!=
nodesListAppend
(
pCols
,
(
SNode
*
)
pCol
))
{
goto
error
;
}
}
FOREACH
(
pNode
,
pRightDesc
->
pSlots
)
{
SSlotDescNode
*
pSlot
=
(
SSlotDescNode
*
)
pNode
;
SColumnNode
*
pCol
=
(
SColumnNode
*
)
nodesMakeNode
(
QUERY_NODE_COLUMN
);
if
(
NULL
==
pCol
)
{
goto
error
;
}
pCol
->
node
.
resType
=
pSlot
->
dataType
;
pCol
->
dataBlockId
=
pRightDesc
->
dataBlockId
;
pCol
->
slotId
=
pSlot
->
slotId
;
pCol
->
colId
=
-
1
;
if
(
TSDB_CODE_SUCCESS
!=
nodesListAppend
(
pCols
,
(
SNode
*
)
pCol
))
{
goto
error
;
}
}
return
pCols
;
error:
nodesDestroyList
(
pCols
);
return
NULL
;
}
static
SPhysiNode
*
createJoinPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SNodeList
*
pChildren
,
SJoinLogicNode
*
pJoinLogicNode
)
{
SJoinPhysiNode
*
pJoin
=
(
SJoinPhysiNode
*
)
makePhysiNode
(
pCxt
,
QUERY_NODE_PHYSICAL_PLAN_JOIN
);
CHECK_ALLOC
(
pJoin
,
NULL
);
SDataBlockDescNode
*
pLeftDesc
=
&
((
SPhysiNode
*
)
nodesListGetNode
(
pChildren
,
0
))
->
outputDataBlockDesc
;
SDataBlockDescNode
*
pRightDesc
=
&
((
SPhysiNode
*
)
nodesListGetNode
(
pChildren
,
1
))
->
outputDataBlockDesc
;
pJoin
->
pOnConditions
=
setNodeSlotId
(
pCxt
,
pLeftDesc
->
dataBlockId
,
pRightDesc
->
dataBlockId
,
pJoinLogicNode
->
pOnConditions
);
CHECK_ALLOC
(
pJoin
->
pOnConditions
,
(
SPhysiNode
*
)
pJoin
);
pJoin
->
pTargets
=
createJoinOutputCols
(
pCxt
,
pLeftDesc
,
pRightDesc
);
CHECK_ALLOC
(
pJoin
->
pTargets
,
(
SPhysiNode
*
)
pJoin
);
CHECK_CODE
(
addDataBlockDesc
(
pCxt
,
pJoin
->
pTargets
,
&
pJoin
->
node
.
outputDataBlockDesc
),
(
SPhysiNode
*
)
pJoin
);
CHECK_CODE
(
setConditionsSlotId
(
pCxt
,
(
const
SLogicNode
*
)
pJoinLogicNode
,
(
SPhysiNode
*
)
pJoin
),
(
SPhysiNode
*
)
pJoin
);
CHECK_CODE
(
setSlotOutput
(
pCxt
,
pJoinLogicNode
->
node
.
pTargets
,
&
pJoin
->
node
.
outputDataBlockDesc
),
(
SPhysiNode
*
)
pJoin
);
return
(
SPhysiNode
*
)
pJoin
;
}
typedef
struct
SRewritePrecalcExprsCxt
{
int32_t
errCode
;
int32_t
planNodeId
;
int32_t
rewriteId
;
SNodeList
*
pPrecalcExprs
;
}
SRewritePrecalcExprsCxt
;
static
EDealRes
collectAndRewrite
(
SRewritePrecalcExprsCxt
*
pCxt
,
SNode
**
pNode
)
{
SNode
*
pExpr
=
nodesCloneNode
(
*
pNode
);
CHECK_ALLOC
(
pExpr
,
DEAL_RES_ERROR
);
if
(
nodesListAppend
(
pCxt
->
pPrecalcExprs
,
pExpr
))
{
nodesDestroyNode
(
pExpr
);
return
DEAL_RES_ERROR
;
}
SColumnNode
*
pCol
=
(
SColumnNode
*
)
nodesMakeNode
(
QUERY_NODE_COLUMN
);
if
(
NULL
==
pCol
)
{
nodesDestroyNode
(
pExpr
);
return
DEAL_RES_ERROR
;
}
SExprNode
*
pRewrittenExpr
=
(
SExprNode
*
)
pExpr
;
pCol
->
node
.
resType
=
pRewrittenExpr
->
resType
;
if
(
'\0'
!=
pRewrittenExpr
->
aliasName
[
0
])
{
strcpy
(
pCol
->
colName
,
pRewrittenExpr
->
aliasName
);
}
else
{
snprintf
(
pRewrittenExpr
->
aliasName
,
sizeof
(
pRewrittenExpr
->
aliasName
),
"#expr_%d_%d"
,
pCxt
->
planNodeId
,
pCxt
->
rewriteId
);
strcpy
(
pCol
->
colName
,
pRewrittenExpr
->
aliasName
);
}
nodesDestroyNode
(
*
pNode
);
*
pNode
=
(
SNode
*
)
pCol
;
return
DEAL_RES_IGNORE_CHILD
;
}
static
EDealRes
doRewritePrecalcExprs
(
SNode
**
pNode
,
void
*
pContext
)
{
SRewritePrecalcExprsCxt
*
pCxt
=
(
SRewritePrecalcExprsCxt
*
)
pContext
;
switch
(
nodeType
(
*
pNode
))
{
case
QUERY_NODE_OPERATOR
:
case
QUERY_NODE_LOGIC_CONDITION
:
{
return
collectAndRewrite
(
pContext
,
pNode
);
}
case
QUERY_NODE_FUNCTION
:
{
if
(
!
fmIsAggFunc
(((
SFunctionNode
*
)(
*
pNode
))
->
funcId
))
{
return
collectAndRewrite
(
pContext
,
pNode
);
}
}
default:
break
;
}
return
DEAL_RES_CONTINUE
;
}
static
int32_t
rewritePrecalcExprs
(
SPhysiPlanContext
*
pCxt
,
SNodeList
*
pList
,
SNodeList
**
pPrecalcExprs
,
SNodeList
**
pRewrittenList
)
{
if
(
NULL
==
pList
)
{
return
TSDB_CODE_SUCCESS
;
}
if
(
NULL
==
*
pPrecalcExprs
)
{
*
pPrecalcExprs
=
nodesMakeList
();
CHECK_ALLOC
(
*
pPrecalcExprs
,
TSDB_CODE_OUT_OF_MEMORY
);
}
if
(
NULL
==
*
pRewrittenList
)
{
*
pRewrittenList
=
nodesMakeList
();
CHECK_ALLOC
(
*
pRewrittenList
,
TSDB_CODE_OUT_OF_MEMORY
);
}
SNode
*
pNode
=
NULL
;
FOREACH
(
pNode
,
pList
)
{
SNode
*
pNew
=
NULL
;
if
(
QUERY_NODE_GROUPING_SET
==
nodeType
(
pNode
))
{
pNew
=
nodesCloneNode
(
nodesListGetNode
(((
SGroupingSetNode
*
)
pNode
)
->
pParameterList
,
0
));
}
else
{
pNew
=
nodesCloneNode
(
pNode
);
}
CHECK_ALLOC
(
pNew
,
TSDB_CODE_OUT_OF_MEMORY
);
CHECK_CODE
(
nodesListAppend
(
*
pRewrittenList
,
pNew
),
TSDB_CODE_OUT_OF_MEMORY
);
}
SRewritePrecalcExprsCxt
cxt
=
{
.
errCode
=
TSDB_CODE_SUCCESS
,
.
pPrecalcExprs
=
*
pPrecalcExprs
};
nodesRewriteList
(
*
pRewrittenList
,
doRewritePrecalcExprs
,
&
cxt
);
if
(
0
==
LIST_LENGTH
(
cxt
.
pPrecalcExprs
))
{
nodesDestroyList
(
cxt
.
pPrecalcExprs
);
*
pPrecalcExprs
=
NULL
;
}
return
cxt
.
errCode
;
}
static
SPhysiNode
*
createAggPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SNodeList
*
pChildren
,
SAggLogicNode
*
pAggLogicNode
)
{
SAggPhysiNode
*
pAgg
=
(
SAggPhysiNode
*
)
makePhysiNode
(
pCxt
,
QUERY_NODE_PHYSICAL_PLAN_AGG
);
CHECK_ALLOC
(
pAgg
,
NULL
);
SNodeList
*
pPrecalcExprs
=
NULL
;
SNodeList
*
pGroupKeys
=
NULL
;
SNodeList
*
pAggFuncs
=
NULL
;
CHECK_CODE
(
rewritePrecalcExprs
(
pCxt
,
pAggLogicNode
->
pGroupKeys
,
&
pPrecalcExprs
,
&
pGroupKeys
),
(
SPhysiNode
*
)
pAgg
);
CHECK_CODE
(
rewritePrecalcExprs
(
pCxt
,
pAggLogicNode
->
pAggFuncs
,
&
pPrecalcExprs
,
&
pAggFuncs
),
(
SPhysiNode
*
)
pAgg
);
SDataBlockDescNode
*
pChildTupe
=
&
(((
SPhysiNode
*
)
nodesListGetNode
(
pChildren
,
0
))
->
outputDataBlockDesc
);
// push down expression to outputDataBlockDesc of child node
if
(
NULL
!=
pPrecalcExprs
)
{
pAgg
->
pExprs
=
setListSlotId
(
pCxt
,
pChildTupe
->
dataBlockId
,
-
1
,
pPrecalcExprs
);
CHECK_ALLOC
(
pAgg
->
pExprs
,
(
SPhysiNode
*
)
pAgg
);
CHECK_CODE
(
addDataBlockDesc
(
pCxt
,
pAgg
->
pExprs
,
pChildTupe
),
(
SPhysiNode
*
)
pAgg
);
}
if
(
NULL
!=
pGroupKeys
)
{
pAgg
->
pGroupKeys
=
setListSlotId
(
pCxt
,
pChildTupe
->
dataBlockId
,
-
1
,
pGroupKeys
);
CHECK_ALLOC
(
pAgg
->
pGroupKeys
,
(
SPhysiNode
*
)
pAgg
);
CHECK_CODE
(
addDataBlockDesc
(
pCxt
,
pAgg
->
pGroupKeys
,
&
pAgg
->
node
.
outputDataBlockDesc
),
(
SPhysiNode
*
)
pAgg
);
}
if
(
NULL
!=
pAggFuncs
)
{
pAgg
->
pAggFuncs
=
setListSlotId
(
pCxt
,
pChildTupe
->
dataBlockId
,
-
1
,
pAggFuncs
);
CHECK_ALLOC
(
pAgg
->
pAggFuncs
,
(
SPhysiNode
*
)
pAgg
);
CHECK_CODE
(
addDataBlockDesc
(
pCxt
,
pAgg
->
pAggFuncs
,
&
pAgg
->
node
.
outputDataBlockDesc
),
(
SPhysiNode
*
)
pAgg
);
}
CHECK_CODE
(
setConditionsSlotId
(
pCxt
,
(
const
SLogicNode
*
)
pAggLogicNode
,
(
SPhysiNode
*
)
pAgg
),
(
SPhysiNode
*
)
pAgg
);
CHECK_CODE
(
setSlotOutput
(
pCxt
,
pAggLogicNode
->
node
.
pTargets
,
&
pAgg
->
node
.
outputDataBlockDesc
),
(
SPhysiNode
*
)
pAgg
);
return
(
SPhysiNode
*
)
pAgg
;
}
static
SPhysiNode
*
createProjectPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SNodeList
*
pChildren
,
SProjectLogicNode
*
pProjectLogicNode
)
{
SProjectPhysiNode
*
pProject
=
(
SProjectPhysiNode
*
)
makePhysiNode
(
pCxt
,
QUERY_NODE_PHYSICAL_PLAN_PROJECT
);
CHECK_ALLOC
(
pProject
,
NULL
);
pProject
->
pProjections
=
setListSlotId
(
pCxt
,
((
SPhysiNode
*
)
nodesListGetNode
(
pChildren
,
0
))
->
outputDataBlockDesc
.
dataBlockId
,
-
1
,
pProjectLogicNode
->
pProjections
);
CHECK_ALLOC
(
pProject
->
pProjections
,
(
SPhysiNode
*
)
pProject
);
CHECK_CODE
(
addDataBlockDesc
(
pCxt
,
pProject
->
pProjections
,
&
pProject
->
node
.
outputDataBlockDesc
),
(
SPhysiNode
*
)
pProject
);
CHECK_CODE
(
setConditionsSlotId
(
pCxt
,
(
const
SLogicNode
*
)
pProjectLogicNode
,
(
SPhysiNode
*
)
pProject
),
(
SPhysiNode
*
)
pProject
);
return
(
SPhysiNode
*
)
pProject
;
}
static
SPhysiNode
*
createPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SLogicNode
*
pLogicPlan
)
{
SNodeList
*
pChildren
=
nodesMakeList
();
CHECK_ALLOC
(
pChildren
,
NULL
);
SNode
*
pLogicChild
;
FOREACH
(
pLogicChild
,
pLogicPlan
->
pChildren
)
{
SNode
*
pChildPhyNode
=
(
SNode
*
)
createPhysiNode
(
pCxt
,
(
SLogicNode
*
)
pLogicChild
);
if
(
TSDB_CODE_SUCCESS
!=
nodesListAppend
(
pChildren
,
pChildPhyNode
))
{
pCxt
->
errCode
=
TSDB_CODE_OUT_OF_MEMORY
;
nodesDestroyList
(
pChildren
);
return
NULL
;
}
}
SPhysiNode
*
pPhyNode
=
NULL
;
switch
(
nodeType
(
pLogicPlan
))
{
case
QUERY_NODE_LOGIC_PLAN_SCAN
:
pPhyNode
=
createScanPhysiNode
(
pCxt
,
(
SScanLogicNode
*
)
pLogicPlan
);
break
;
case
QUERY_NODE_LOGIC_PLAN_JOIN
:
pPhyNode
=
createJoinPhysiNode
(
pCxt
,
pChildren
,
(
SJoinLogicNode
*
)
pLogicPlan
);
break
;
case
QUERY_NODE_LOGIC_PLAN_AGG
:
pPhyNode
=
createAggPhysiNode
(
pCxt
,
pChildren
,
(
SAggLogicNode
*
)
pLogicPlan
);
break
;
case
QUERY_NODE_LOGIC_PLAN_PROJECT
:
pPhyNode
=
createProjectPhysiNode
(
pCxt
,
pChildren
,
(
SProjectLogicNode
*
)
pLogicPlan
);
break
;
default:
break
;
}
pPhyNode
->
pChildren
=
pChildren
;
SNode
*
pChild
;
FOREACH
(
pChild
,
pPhyNode
->
pChildren
)
{
((
SPhysiNode
*
)
pChild
)
->
pParent
=
pPhyNode
;
}
return
pPhyNode
;
}
int32_t
createPhysiPlan
(
SLogicNode
*
pLogicNode
,
SPhysiNode
**
pPhyNode
)
{
SPhysiPlanContext
cxt
=
{
.
errCode
=
TSDB_CODE_SUCCESS
,
.
nextDataBlockId
=
0
,
.
pLocationHelper
=
taosArrayInit
(
32
,
POINTER_BYTES
)
};
if
(
NULL
==
cxt
.
pLocationHelper
)
{
return
TSDB_CODE_OUT_OF_MEMORY
;
}
*
pPhyNode
=
createPhysiNode
(
&
cxt
,
pLogicNode
);
return
cxt
.
errCode
;
}
int32_t
buildPhysiPlan
(
SPlanContext
*
pCxt
,
SLogicNode
*
pLogicNode
,
SQueryPlan
**
pPlan
)
{
// split
// scale out
// maping
// create
return
TSDB_CODE_SUCCESS
;
}
source/libs/planner/src/physicalPlanJson.c
已删除
100644 → 0
浏览文件 @
768e0593
/*
* 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/>.
*/
#if 0
#include "plannerInt.h"
#include "parser.h"
#include "cJSON.h"
typedef bool (*FToJson)(const void* obj, cJSON* json);
typedef bool (*FFromJson)(const cJSON* json, void* obj);
static char* getString(const cJSON* json, const char* name) {
char* p = cJSON_GetStringValue(cJSON_GetObjectItem(json, name));
return strdup(p);
}
static void copyString(const cJSON* json, const char* name, char* dst) {
strcpy(dst, cJSON_GetStringValue(cJSON_GetObjectItem(json, name)));
}
static uint64_t getBigintFromString(const cJSON* json, const char* name) {
char* val = getString(json, name);
uint64_t intVal = strtoul(val, NULL, 10);
tfree(val);
return intVal;
}
static int64_t getNumber(const cJSON* json, const char* name) {
double d = cJSON_GetNumberValue(cJSON_GetObjectItem(json, name));
return (int64_t) d;
}
static bool addObject(cJSON* json, const char* name, FToJson func, const void* obj) {
if (NULL == obj) {
return true;
}
cJSON* jObj = cJSON_CreateObject();
if (NULL == jObj || !func(obj, jObj)) {
cJSON_Delete(jObj);
return false;
}
return cJSON_AddItemToObject(json, name, jObj);
}
static bool addItem(cJSON* json, FToJson func, const void* obj) {
cJSON* jObj = cJSON_CreateObject();
if (NULL == jObj || !func(obj, jObj)) {
cJSON_Delete(jObj);
return false;
}
return cJSON_AddItemToArray(json, jObj);
}
static bool fromObject(const cJSON* json, const char* name, FFromJson func, void* obj, bool required) {
cJSON* jObj = cJSON_GetObjectItem(json, name);
if (NULL == jObj) {
return !required;
}
return func(jObj, obj);
}
static bool fromObjectWithAlloc(const cJSON* json, const char* name, FFromJson func, void** obj, int32_t size, bool required) {
cJSON* jObj = cJSON_GetObjectItem(json, name);
if (NULL == jObj) {
return !required;
}
*obj = calloc(1, size);
if (NULL == *obj) {
return false;
}
return func(jObj, *obj);
}
static const char* jkPnodeType = "Type";
static int32_t getPnodeTypeSize(cJSON* json) {
switch (getNumber(json, jkPnodeType)) {
case OP_StreamScan:
case OP_TableScan:
case OP_TableSeqScan:
return sizeof(STableScanPhyNode);
case OP_TagScan:
return sizeof(STagScanPhyNode);
case OP_SystemTableScan:
return sizeof(SSystemTableScanPhyNode);
case OP_Aggregate:
return sizeof(SAggPhyNode);
case OP_Exchange:
return sizeof(SExchangePhyNode);
default:
break;
};
return -1;
}
static bool fromPnode(const cJSON* json, const char* name, FFromJson func, void** obj) {
cJSON* jObj = cJSON_GetObjectItem(json, name);
if (NULL == jObj) {
return true;
}
*obj = calloc(1, getPnodeTypeSize(jObj));
if (NULL == *obj) {
return false;
}
return func(jObj, *obj);
}
static bool fromPnodeArray(const cJSON* json, const char* name, FFromJson func, SArray** array) {
const cJSON* jArray = cJSON_GetObjectItem(json, name);
int32_t size = (NULL == jArray ? 0 : cJSON_GetArraySize(jArray));
if (size > 0) {
*array = taosArrayInit(size, POINTER_BYTES);
if (NULL == *array) {
return false;
}
}
for (int32_t i = 0; i < size; ++i) {
cJSON* jItem = cJSON_GetArrayItem(jArray, i);
void* item = calloc(1, getPnodeTypeSize(jItem));
if (NULL == item || !func(jItem, item)) {
return false;
}
taosArrayPush(*array, &item);
}
return true;
}
static bool addTarray(cJSON* json, const char* name, FToJson func, const SArray* array, bool isPoint) {
size_t size = (NULL == array) ? 0 : taosArrayGetSize(array);
if (size > 0) {
cJSON* jArray = cJSON_AddArrayToObject(json, name);
if (NULL == jArray) {
return false;
}
for (size_t i = 0; i < size; ++i) {
if (!addItem(jArray, func, isPoint ? taosArrayGetP(array, i) : taosArrayGet(array, i))) {
return false;
}
}
}
return true;
}
static bool addInlineArray(cJSON* json, const char* name, FToJson func, const SArray* array) {
return addTarray(json, name, func, array, false);
}
static bool addArray(cJSON* json, const char* name, FToJson func, const SArray* array) {
return addTarray(json, name, func, array, true);
}
static bool fromTarray(const cJSON* json, const char* name, FFromJson func, SArray** array, int32_t itemSize, bool isPoint) {
const cJSON* jArray = cJSON_GetObjectItem(json, name);
int32_t size = (NULL == jArray ? 0 : cJSON_GetArraySize(jArray));
if (size > 0) {
*array = taosArrayInit(size, isPoint ? POINTER_BYTES : itemSize);
if (NULL == *array) {
return false;
}
}
for (int32_t i = 0; i < size; ++i) {
void* item = calloc(1, itemSize);
if (NULL == item || !func(cJSON_GetArrayItem(jArray, i), item)) {
return false;
}
taosArrayPush(*array, isPoint ? &item : item);
}
return true;
}
static bool fromInlineArray(const cJSON* json, const char* name, FFromJson func, SArray** array, int32_t itemSize) {
return fromTarray(json, name, func, array, itemSize, false);
}
static bool fromArray(const cJSON* json, const char* name, FFromJson func, SArray** array, int32_t itemSize) {
return fromTarray(json, name, func, array, itemSize, true);
}
static bool addRawArray(cJSON* json, const char* name, FToJson func, const void* array, int32_t itemSize, int32_t size) {
if (size > 0) {
cJSON* jArray = cJSON_AddArrayToObject(json, name);
if (NULL == jArray) {
return false;
}
for (size_t i = 0; i < size; ++i) {
if (!addItem(jArray, func, (const char*)array + itemSize * i)) {
return false;
}
}
}
return true;
}
static const cJSON* getArray(const cJSON* json, const char* name, int32_t* size) {
const cJSON* jArray = cJSON_GetObjectItem(json, name);
*size = (NULL == jArray ? 0 : cJSON_GetArraySize(jArray));
return jArray;
}
static bool fromItem(const cJSON* jArray, FFromJson func, void* array, int32_t itemSize, int32_t size) {
for (int32_t i = 0; i < size; ++i) {
if (!func(cJSON_GetArrayItem(jArray, i), (char*)array + itemSize * i)) {
return false;
}
}
return true;
}
static bool fromRawArrayWithAlloc(const cJSON* json, const char* name, FFromJson func, void** array, int32_t itemSize, int32_t* size) {
const cJSON* jArray = getArray(json, name, size);
if (*size > 0) {
*array = calloc(1, itemSize * (*size));
if (NULL == *array) {
return false;
}
}
return fromItem(jArray, func, *array, itemSize, *size);
}
static bool fromRawArray(const cJSON* json, const char* name, FFromJson func, void* array, int32_t itemSize, int32_t* size) {
const cJSON* jArray = getArray(json, name, size);
return fromItem(jArray, func, array, itemSize, *size);
}
static const char* jkSchemaType = "Type";
static const char* jkSchemaColId = "ColId";
static const char* jkSchemaBytes = "Bytes";
// The 'name' field do not need to be serialized.
static bool schemaToJson(const void* obj, cJSON* jSchema) {
const SSlotSchema* schema = (const SSlotSchema*)obj;
bool res = cJSON_AddNumberToObject(jSchema, jkSchemaType, schema->type);
if (res) {
res = cJSON_AddNumberToObject(jSchema, jkSchemaColId, schema->colId);
}
if (res) {
res = cJSON_AddNumberToObject(jSchema, jkSchemaBytes, schema->bytes);
}
return res;
}
static bool schemaFromJson(const cJSON* json, void* obj) {
SSlotSchema* schema = (SSlotSchema*)obj;
schema->type = getNumber(json, jkSchemaType);
schema->colId = getNumber(json, jkSchemaColId);
schema->bytes = getNumber(json, jkSchemaBytes);
return true;
}
static const char* jkDataBlockSchemaSlotSchema = "SlotSchema";
static const char* jkDataBlockSchemaResultRowSize = "resultRowSize";
static const char* jkDataBlockSchemaPrecision = "Precision";
static bool dataBlockSchemaToJson(const void* obj, cJSON* json) {
const SDataBlockSchema* schema = (const SDataBlockSchema*)obj;
bool res = addRawArray(json, jkDataBlockSchemaSlotSchema, schemaToJson, schema->pSchema, sizeof(SSlotSchema), schema->numOfCols);
if (res) {
res = cJSON_AddNumberToObject(json, jkDataBlockSchemaResultRowSize, schema->resultRowSize);
}
if (res) {
res = cJSON_AddNumberToObject(json, jkDataBlockSchemaPrecision, schema->precision);
}
return res;
}
static bool dataBlockSchemaFromJson(const cJSON* json, void* obj) {
SDataBlockSchema* schema = (SDataBlockSchema*)obj;
schema->resultRowSize = getNumber(json, jkDataBlockSchemaResultRowSize);
schema->precision = getNumber(json, jkDataBlockSchemaPrecision);
return fromRawArrayWithAlloc(json, jkDataBlockSchemaSlotSchema, schemaFromJson, (void**)&(schema->pSchema), sizeof(SSlotSchema), &schema->numOfCols);
}
static const char* jkColumnFilterInfoLowerRelOptr = "LowerRelOptr";
static const char* jkColumnFilterInfoUpperRelOptr = "UpperRelOptr";
static const char* jkColumnFilterInfoFilterstr = "Filterstr";
static const char* jkColumnFilterInfoLowerBnd = "LowerBnd";
static const char* jkColumnFilterInfoUpperBnd = "UpperBnd";
static bool columnFilterInfoToJson(const void* obj, cJSON* jFilter) {
const SColumnFilterInfo* filter = (const SColumnFilterInfo*)obj;
bool res = cJSON_AddNumberToObject(jFilter, jkColumnFilterInfoLowerRelOptr, filter->lowerRelOptr);
if (res) {
res = cJSON_AddNumberToObject(jFilter, jkColumnFilterInfoUpperRelOptr, filter->upperRelOptr);
}
if (res) {
res = cJSON_AddNumberToObject(jFilter, jkColumnFilterInfoFilterstr, filter->filterstr);
}
if (res) {
res = cJSON_AddNumberToObject(jFilter, jkColumnFilterInfoLowerBnd, filter->lowerBndd);
}
if (res) {
res = cJSON_AddNumberToObject(jFilter, jkColumnFilterInfoUpperBnd, filter->upperBndd);
}
return res;
}
static bool columnFilterInfoFromJson(const cJSON* json, void* obj) {
SColumnFilterInfo* filter = (SColumnFilterInfo*)obj;
filter->lowerRelOptr = getNumber(json, jkColumnFilterInfoLowerRelOptr);
filter->upperRelOptr = getNumber(json, jkColumnFilterInfoUpperRelOptr);
filter->filterstr = getNumber(json, jkColumnFilterInfoFilterstr);
filter->lowerBndd = getNumber(json, jkColumnFilterInfoLowerBnd);
filter->upperBndd = getNumber(json, jkColumnFilterInfoUpperBnd);
return true;
}
static const char* jkColumnInfoColId = "ColId";
static const char* jkColumnInfoType = "Type";
static const char* jkColumnInfoBytes = "Bytes";
static const char* jkColumnInfoFilterList = "FilterList";
static bool columnInfoToJson(const void* obj, cJSON* jCol) {
const SColumnInfo* col = (const SColumnInfo*)obj;
bool res = cJSON_AddNumberToObject(jCol, jkColumnInfoColId, col->colId);
if (res) {
res = cJSON_AddNumberToObject(jCol, jkColumnInfoType, col->type);
}
if (res) {
res = cJSON_AddNumberToObject(jCol, jkColumnInfoBytes, col->bytes);
}
if (res) { // TODO: temporarily disable it
// res = addRawArray(jCol, jkColumnInfoFilterList, columnFilterInfoToJson, col->flist.filterInfo, sizeof(SColumnFilterInfo), col->flist.numOfFilters);
}
return res;
}
static bool columnInfoFromJson(const cJSON* json, void* obj) {
SColumnInfo* col = (SColumnInfo*)obj;
col->colId = getNumber(json, jkColumnInfoColId);
col->type = getNumber(json, jkColumnInfoType);
col->bytes = getNumber(json, jkColumnInfoBytes);
int32_t size = 0;
bool res = fromRawArrayWithAlloc(json, jkColumnInfoFilterList, columnFilterInfoFromJson, (void**)&col->flist.filterInfo, sizeof(SColumnFilterInfo), &size);
col->flist.numOfFilters = size;
return res;
}
static const char* jkColumnTableId = "TableId";
static const char* jkColumnFlag = "Flag";
static const char* jkColumnInfo = "Info";
static bool columnToJson(const void* obj, cJSON* jCol) {
const SColumn* col = (const SColumn*)obj;
bool res = cJSON_AddNumberToObject(jCol, jkColumnTableId, col->uid);
if (res) {
res = cJSON_AddNumberToObject(jCol, jkColumnFlag, col->flag);
}
if (res) {
res = addObject(jCol, jkColumnInfo, columnInfoToJson, &col->info);
}
return res;
}
static bool columnFromJson(const cJSON* json, void* obj) {
SColumn* col = (SColumn*)obj;
col->uid = getNumber(json, jkColumnTableId);
col->flag = getNumber(json, jkColumnFlag);
return fromObject(json, jkColumnInfo, columnInfoFromJson, &col->info, true);
}
static bool exprNodeToJson(const void* obj, cJSON* jExprInfo);
static bool exprNodeFromJson(const cJSON* json, void* obj);
static const char* jkExprNodeOper = "Oper";
static const char* jkExprNodeLeft = "Left";
static const char* jkExprNodeRight = "Right";
static bool operatorToJson(const void* obj, cJSON* jOper) {
const tExprNode* exprInfo = (const tExprNode*)obj;
bool res = cJSON_AddNumberToObject(jOper, jkExprNodeOper, exprInfo->_node.optr);
if (res) {
res = addObject(jOper, jkExprNodeLeft, exprNodeToJson, exprInfo->_node.pLeft);
}
if (res) {
res = addObject(jOper, jkExprNodeRight, exprNodeToJson, exprInfo->_node.pRight);
}
return res;
}
static bool operatorFromJson(const cJSON* json, void* obj) {
tExprNode* exprInfo = (tExprNode*)obj;
exprInfo->_node.optr = getNumber(json, jkExprNodeOper);
bool res = fromObject(json, jkExprNodeLeft, exprNodeFromJson, exprInfo->_node.pLeft, false);
if (res) {
res = fromObject(json, jkExprNodeRight, exprNodeFromJson, exprInfo->_node.pRight, false);
}
return res;
}
static const char* jkFunctionName = "Name";
static const char* jkFunctionChild = "Child";
static bool functionToJson(const void* obj, cJSON* jFunc) {
const tExprNode* exprInfo = (const tExprNode*)obj;
bool res = cJSON_AddStringToObject(jFunc, jkFunctionName, exprInfo->_function.functionName);
if (res && NULL != exprInfo->_function.pChild) {
res = addRawArray(jFunc, jkFunctionChild, exprNodeToJson, exprInfo->_function.pChild, sizeof(tExprNode*), exprInfo->_function.num);
}
return res;
}
static bool functionFromJson(const cJSON* json, void* obj) {
tExprNode* exprInfo = (tExprNode*)obj;
copyString(json, jkFunctionName, exprInfo->_function.functionName);
exprInfo->_function.pChild = calloc(1, sizeof(tExprNode*));
if (NULL == exprInfo->_function.pChild) {
return false;
}
return fromRawArrayWithAlloc(json, jkFunctionChild, exprNodeFromJson, (void**)exprInfo->_function.pChild, sizeof(tExprNode*), &exprInfo->_function.num);
}
static const char* jkVariantType = "Type";
static const char* jkVariantLen = "Len";
static const char* jkVariantvalues = "values";
static const char* jkVariantValue = "Value";
static bool variantToJson(const void* obj, cJSON* jVar) {
const SVariant* var = (const SVariant*)obj;
bool res = cJSON_AddNumberToObject(jVar, jkVariantType, var->nType);
if (res) {
res = cJSON_AddNumberToObject(jVar, jkVariantLen, var->nLen);
}
if (res) {
if (0/* in */) {
res = addArray(jVar, jkVariantvalues, variantToJson, var->arr);
} else if (IS_NUMERIC_TYPE(var->nType)) {
res = cJSON_AddNumberToObject(jVar, jkVariantValue, var->d);
} else {
res = cJSON_AddStringToObject(jVar, jkVariantValue, var->pz);
}
}
return res;
}
static bool variantFromJson(const cJSON* json, void* obj) {
SVariant* var = (SVariant*)obj;
var->nType = getNumber(json, jkVariantType);
var->nLen = getNumber(json, jkVariantLen);
if (0/* in */) {
return fromArray(json, jkVariantvalues, variantFromJson, &var->arr, sizeof(SVariant));
} else if (IS_NUMERIC_TYPE(var->nType)) {
var->d = getNumber(json, jkVariantValue);
} else {
var->pz = getString(json, jkVariantValue);
}
return true;
}
static const char* jkExprNodeType = "Type";
static const char* jkExprNodeOperator = "Operator";
static const char* jkExprNodeFunction = "Function";
static const char* jkExprNodeColumn = "Column";
static const char* jkExprNodeValue = "Value";
static bool exprNodeToJson(const void* obj, cJSON* jExprInfo) {
const tExprNode* exprInfo = *(const tExprNode**)obj;
bool res = cJSON_AddNumberToObject(jExprInfo, jkExprNodeType, exprInfo->nodeType);
if (res) {
switch (exprInfo->nodeType) {
case TEXPR_BINARYEXPR_NODE:
case TEXPR_UNARYEXPR_NODE:
res = addObject(jExprInfo, jkExprNodeOperator, operatorToJson, exprInfo);
break;
case TEXPR_FUNCTION_NODE:
res = addObject(jExprInfo, jkExprNodeFunction, functionToJson, exprInfo);
break;
case TEXPR_COL_NODE:
res = addObject(jExprInfo, jkExprNodeColumn, schemaToJson, exprInfo->pSchema);
break;
case TEXPR_VALUE_NODE:
res = addObject(jExprInfo, jkExprNodeValue, variantToJson, exprInfo->pVal);
break;
default:
res = false;
break;
}
}
return res;
}
static bool exprNodeFromJson(const cJSON* json, void* obj) {
tExprNode* exprInfo = (tExprNode*)obj;
exprInfo->nodeType = getNumber(json, jkExprNodeType);
switch (exprInfo->nodeType) {
case TEXPR_BINARYEXPR_NODE:
case TEXPR_UNARYEXPR_NODE:
return fromObject(json, jkExprNodeOperator, operatorFromJson, exprInfo, false);
case TEXPR_FUNCTION_NODE:
return fromObject(json, jkExprNodeFunction, functionFromJson, exprInfo, false);
case TEXPR_COL_NODE:
return fromObjectWithAlloc(json, jkExprNodeColumn, schemaFromJson, (void**)&exprInfo->pSchema, sizeof(SSchema), false);
case TEXPR_VALUE_NODE:
return fromObject(json, jkExprNodeValue, variantFromJson, exprInfo->pVal, false);
default:
break;
}
return false;
}
static const char* jkSqlExprSchema = "Schema";
static const char* jkSqlExprColumns = "Columns";
static const char* jkSqlExprInterBytes = "InterBytes";
static const char* jkSqlExprParams = "Params";
// token does not need to be serialized.
static bool sqlExprToJson(const void* obj, cJSON* jExpr) {
const SSqlExpr* expr = (const SSqlExpr*)obj;
bool res = addObject(jExpr, jkSqlExprSchema, schemaToJson, &expr->resSchema);
if (res) {
res = addRawArray(jExpr, jkSqlExprColumns, columnToJson, expr->pColumns, sizeof(SColumn), expr->numOfCols);
}
if (res) {
res = cJSON_AddNumberToObject(jExpr, jkSqlExprInterBytes, expr->interBytes);
}
if (res) {
res = addRawArray(jExpr, jkSqlExprParams, variantToJson, expr->param, sizeof(SVariant), expr->numOfParams);
}
return res;
}
static bool sqlExprFromJson(const cJSON* json, void* obj) {
SSqlExpr* expr = (SSqlExpr*)obj;
bool res = fromObject(json, jkSqlExprSchema, schemaFromJson, &expr->resSchema, false);
if (res) {
res = fromRawArrayWithAlloc(json, jkSqlExprColumns, columnFromJson, (void**)&expr->pColumns, sizeof(SColumn), &expr->numOfCols);
}
if (res) {
expr->interBytes = getNumber(json, jkSqlExprInterBytes);
}
if (res) {
int32_t size = 0;
res = fromRawArray(json, jkSqlExprParams, variantFromJson, expr->param, sizeof(SVariant), &size);
expr->numOfParams = size;
}
return res;
}
static const char* jkExprInfoBase = "Base";
static const char* jkExprInfoExpr = "Expr";
static bool exprInfoToJson(const void* obj, cJSON* jExprInfo) {
const SExprInfo* exprInfo = (const SExprInfo*)obj;
bool res = addObject(jExprInfo, jkExprInfoBase, sqlExprToJson, &exprInfo->base);
if (res) {
res = addObject(jExprInfo, jkExprInfoExpr, exprNodeToJson, &exprInfo->pExpr);
}
return res;
}
static bool exprInfoFromJson(const cJSON* json, void* obj) {
SExprInfo* exprInfo = (SExprInfo*)obj;
bool res = fromObject(json, jkExprInfoBase, sqlExprFromJson, &exprInfo->base, true);
if (res) {
res = fromObjectWithAlloc(json, jkExprInfoExpr, exprNodeFromJson, (void**)&exprInfo->pExpr, sizeof(tExprNode), true);
}
return res;
}
static const char* jkTimeWindowStartKey = "StartKey";
static const char* jkTimeWindowEndKey = "EndKey";
static bool timeWindowToJson(const void* obj, cJSON* json) {
const STimeWindow* win = (const STimeWindow*)obj;
char tmp[40] = {0};
snprintf(tmp, tListLen(tmp),"%"PRId64, win->skey);
bool res = cJSON_AddStringToObject(json, jkTimeWindowStartKey, tmp);
if (res) {
memset(tmp, 0, tListLen(tmp));
snprintf(tmp, tListLen(tmp),"%"PRId64, win->ekey);
res = cJSON_AddStringToObject(json, jkTimeWindowEndKey, tmp);
}
return res;
}
static bool timeWindowFromJson(const cJSON* json, void* obj) {
STimeWindow* win = (STimeWindow*)obj;
win->skey = getBigintFromString(json, jkTimeWindowStartKey);
win->ekey = getBigintFromString(json, jkTimeWindowEndKey);
return true;
}
static const char* jkScanNodeTableId = "TableId";
static const char* jkScanNodeTableType = "TableType";
static const char* jkScanNodeTableOrder = "Order";
static const char* jkScanNodeTableCount = "Count";
static const char* jkScanNodeTableRevCount = "Reverse";
static bool scanNodeToJson(const void* obj, cJSON* json) {
const SScanPhyNode* pNode = (const SScanPhyNode*)obj;
char uid[40] = {0};
snprintf(uid, tListLen(uid), "%"PRIu64, pNode->uid);
bool res = cJSON_AddStringToObject(json, jkScanNodeTableId, uid);
if (res) {
res = cJSON_AddNumberToObject(json, jkScanNodeTableType, pNode->tableType);
}
if (res) {
res = cJSON_AddNumberToObject(json, jkScanNodeTableOrder, pNode->order);
}
if (res) {
res = cJSON_AddNumberToObject(json, jkScanNodeTableCount, pNode->count);
}
if (res) {
res = cJSON_AddNumberToObject(json, jkScanNodeTableRevCount, pNode->reverse);
}
return res;
}
static bool scanNodeFromJson(const cJSON* json, void* obj) {
SScanPhyNode* pNode = (SScanPhyNode*)obj;
pNode->uid = getBigintFromString(json, jkScanNodeTableId);
pNode->tableType = getNumber(json, jkScanNodeTableType);
pNode->count = getNumber(json, jkScanNodeTableCount);
pNode->order = getNumber(json, jkScanNodeTableOrder);
pNode->reverse = getNumber(json, jkScanNodeTableRevCount);
return true;
}
static const char* jkColIndexColId = "ColId";
static const char* jkColIndexColIndex = "ColIndex";
static const char* jkColIndexFlag = "Flag";
static const char* jkColIndexName = "Name";
static bool colIndexToJson(const void* obj, cJSON* json) {
const SColIndex* col = (const SColIndex*)obj;
bool res = cJSON_AddNumberToObject(json, jkColIndexColId, col->colId);
if (res) {
res = cJSON_AddNumberToObject(json, jkColIndexColIndex, col->colIndex);
}
if (res) {
res = cJSON_AddNumberToObject(json, jkColIndexFlag, col->flag);
}
if (res) {
res = cJSON_AddStringToObject(json, jkColIndexName, col->name);
}
return res;
}
static bool colIndexFromJson(const cJSON* json, void* obj) {
SColIndex* col = (SColIndex*)obj;
col->colId = getNumber(json, jkColIndexColId);
col->colIndex = getNumber(json, jkColIndexColIndex);
col->flag = getNumber(json, jkColIndexFlag);
copyString(json, jkColIndexName, col->name);
return true;
}
static const char* jkAggNodeAggAlgo = "AggAlgo";
static const char* jkAggNodeAggSplit = "AggSplit";
static const char* jkAggNodeExprs = "Exprs";
static const char* jkAggNodeGroupByList = "GroupByList";
static bool aggNodeToJson(const void* obj, cJSON* json) {
const SAggPhyNode* agg = (const SAggPhyNode*)obj;
bool res = cJSON_AddNumberToObject(json, jkAggNodeAggAlgo, agg->aggAlgo);
if (res) {
res = cJSON_AddNumberToObject(json, jkAggNodeAggSplit, agg->aggSplit);
}
if (res) {
res = addArray(json, jkAggNodeExprs, exprInfoToJson, agg->pExprs);
}
if (res) {
res = addArray(json, jkAggNodeGroupByList, colIndexToJson, agg->pGroupByList);
}
return res;
}
static bool aggNodeFromJson(const cJSON* json, void* obj) {
SAggPhyNode* agg = (SAggPhyNode*)obj;
agg->aggAlgo = getNumber(json, jkAggNodeAggAlgo);
agg->aggSplit = getNumber(json, jkAggNodeAggSplit);
bool res = fromArray(json, jkAggNodeExprs, exprInfoFromJson, &agg->pExprs, sizeof(SExprInfo));
if (res) {
res = fromArray(json, jkAggNodeGroupByList, colIndexFromJson, &agg->pGroupByList, sizeof(SExprInfo));
}
return res;
}
static const char* jkTableScanNodeFlag = "Flag";
static const char* jkTableScanNodeWindow = "Window";
static const char* jkTableScanNodeTagsConditions = "TagsConditions";
static bool tableScanNodeToJson(const void* obj, cJSON* json) {
const STableScanPhyNode* scan = (const STableScanPhyNode*)obj;
bool res = scanNodeToJson(obj, json);
if (res) {
res = cJSON_AddNumberToObject(json, jkTableScanNodeFlag, scan->scanFlag);
}
if (res) {
res = addObject(json, jkTableScanNodeWindow, timeWindowToJson, &scan->window);
}
if (res) {
res = addArray(json, jkTableScanNodeTagsConditions, exprInfoToJson, scan->pTagsConditions);
}
return res;
}
static bool tableScanNodeFromJson(const cJSON* json, void* obj) {
STableScanPhyNode* scan = (STableScanPhyNode*)obj;
bool res = scanNodeFromJson(json, obj);
if (res) {
scan->scanFlag = getNumber(json, jkTableScanNodeFlag);
}
if (res) {
res = fromObject(json, jkTableScanNodeWindow, timeWindowFromJson, &scan->window, true);
}
if (res) {
res = fromArray(json, jkTableScanNodeTagsConditions, exprInfoFromJson, &scan->pTagsConditions, sizeof(SExprInfo));
}
return res;
}
static const char* jkEpAddrFqdn = "Fqdn";
static const char* jkEpAddrPort = "Port";
static bool epAddrToJson(const void* obj, cJSON* json) {
const SEp* ep = (const SEp*)obj;
bool res = cJSON_AddStringToObject(json, jkEpAddrFqdn, ep->fqdn);
if (res) {
res = cJSON_AddNumberToObject(json, jkEpAddrPort, ep->port);
}
return res;
}
static bool epAddrFromJson(const cJSON* json, void* obj) {
SEp* ep = (SEp*)obj;
copyString(json, jkEpAddrFqdn, ep->fqdn);
ep->port = getNumber(json, jkEpAddrPort);
return true;
}
static const char* jkNodeAddrId = "NodeId";
static const char* jkNodeAddrInUse = "InUse";
static const char* jkNodeAddrEpAddrs = "Ep";
static const char* jkNodeAddr = "NodeAddr";
static const char* jkNodeTaskId = "TaskId";
static const char* jkNodeTaskSchedId = "SchedId";
static bool queryNodeAddrToJson(const void* obj, cJSON* json) {
const SQueryNodeAddr* pAddr = (const SQueryNodeAddr*) obj;
bool res = cJSON_AddNumberToObject(json, jkNodeAddrId, pAddr->nodeId);
if (res) {
res = cJSON_AddNumberToObject(json, jkNodeAddrInUse, pAddr->epset.inUse);
}
if (res) {
res = addRawArray(json, jkNodeAddrEpAddrs, epAddrToJson, pAddr->epset.eps, sizeof(SEp), pAddr->epset.numOfEps);
}
return res;
}
static bool queryNodeAddrFromJson(const cJSON* json, void* obj) {
SQueryNodeAddr* pAddr = (SQueryNodeAddr*) obj;
pAddr->nodeId = getNumber(json, jkNodeAddrId);
pAddr->epset.inUse = getNumber(json, jkNodeAddrInUse);
int32_t numOfEps = 0;
bool res = fromRawArray(json, jkNodeAddrEpAddrs, epAddrFromJson, pAddr->epset.eps, sizeof(SEp), &numOfEps);
pAddr->epset.numOfEps = numOfEps;
return res;
}
static bool nodeAddrToJson(const void* obj, cJSON* json) {
const SDownstreamSource* pSource = (const SDownstreamSource*) obj;
bool res = cJSON_AddNumberToObject(json, jkNodeTaskId, pSource->taskId);
if (res) {
char t[30] = {0};
snprintf(t, tListLen(t), "%"PRIu64, pSource->schedId);
res = cJSON_AddStringToObject(json, jkNodeTaskSchedId, t);
}
if (res) {
res = addObject(json, jkNodeAddr, queryNodeAddrToJson, &pSource->addr);
}
return res;
}
static bool nodeAddrFromJson(const cJSON* json, void* obj) {
SDownstreamSource* pSource = (SDownstreamSource*)obj;
pSource->taskId = getNumber(json, jkNodeTaskId);
pSource->schedId = getBigintFromString(json, jkNodeTaskSchedId);
bool res = fromObject(json, jkNodeAddr, queryNodeAddrFromJson, &pSource->addr, true);
return res;
}
static const char* jkExchangeNodeSrcTemplateId = "SrcTemplateId";
static const char* jkExchangeNodeSrcEndPoints = "SrcAddrs";
static bool exchangeNodeToJson(const void* obj, cJSON* json) {
const SExchangePhyNode* exchange = (const SExchangePhyNode*)obj;
bool res = cJSON_AddNumberToObject(json, jkExchangeNodeSrcTemplateId, exchange->srcTemplateId);
if (res) {
res = addRawArray(json, jkExchangeNodeSrcEndPoints, nodeAddrToJson, exchange->pSrcEndPoints->pData, sizeof(SDownstreamSource), taosArrayGetSize(exchange->pSrcEndPoints));
}
return res;
}
static bool exchangeNodeFromJson(const cJSON* json, void* obj) {
SExchangePhyNode* exchange = (SExchangePhyNode*)obj;
exchange->srcTemplateId = getNumber(json, jkExchangeNodeSrcTemplateId);
return fromInlineArray(json, jkExchangeNodeSrcEndPoints, nodeAddrFromJson, &exchange->pSrcEndPoints, sizeof(SDownstreamSource));
}
static bool specificPhyNodeToJson(const void* obj, cJSON* json) {
const SPhyNode* phyNode = (const SPhyNode*)obj;
switch (phyNode->info.type) {
case OP_StreamScan:
case OP_TableScan:
case OP_TableSeqScan:
return tableScanNodeToJson(obj, json);
case OP_TagScan:
case OP_SystemTableScan:
return scanNodeToJson(obj, json);
case OP_Aggregate:
return aggNodeToJson(obj, json);
case OP_Project:
return true;
// case OP_Groupby:
case OP_Limit:
case OP_SLimit:
case OP_TimeWindow:
case OP_SessionWindow:
case OP_StateWindow:
case OP_Fill:
case OP_MultiTableAggregate:
case OP_MultiTableTimeInterval:
case OP_Filter:
case OP_Distinct:
case OP_Join:
case OP_AllTimeWindow:
case OP_AllMultiTableTimeInterval:
case OP_Order:
break; // todo
case OP_Exchange:
return exchangeNodeToJson(obj, json);
default:
break;
}
return false;
}
static bool specificPhyNodeFromJson(const cJSON* json, void* obj) {
SPhyNode* phyNode = (SPhyNode*)obj;
switch (phyNode->info.type) {
case OP_StreamScan:
case OP_TableScan:
case OP_TableSeqScan:
return tableScanNodeFromJson(json, obj);
case OP_TagScan:
case OP_SystemTableScan:
return scanNodeFromJson(json, obj);
case OP_Aggregate:
return aggNodeFromJson(json, obj);
case OP_Project:
return true;
// case OP_Groupby:
case OP_Limit:
case OP_SLimit:
case OP_TimeWindow:
case OP_SessionWindow:
case OP_StateWindow:
case OP_Fill:
case OP_MultiTableAggregate:
case OP_MultiTableTimeInterval:
case OP_Filter:
case OP_Distinct:
case OP_Join:
case OP_AllTimeWindow:
case OP_AllMultiTableTimeInterval:
case OP_Order:
break; // todo
case OP_Exchange:
return exchangeNodeFromJson(json, obj);
default:
break;
}
return false;
}
static const char* jkPnodeName = "Name";
static const char* jkPnodeTargets = "Targets";
static const char* jkPnodeConditions = "Conditions";
static const char* jkPnodeSchema = "TargetSchema";
static const char* jkPnodeChildren = "Children";
// The 'pParent' field do not need to be serialized.
static bool phyNodeToJson(const void* obj, cJSON* jNode) {
const SPhyNode* phyNode = (const SPhyNode*)obj;
bool res = cJSON_AddNumberToObject(jNode, jkPnodeType, phyNode->info.type);
if (res) {
res = cJSON_AddStringToObject(jNode, jkPnodeName, phyNode->info.name);
}
if (res) {
res = addArray(jNode, jkPnodeTargets, exprInfoToJson, phyNode->pTargets);
}
if (res) {
res = addArray(jNode, jkPnodeConditions, exprInfoToJson, phyNode->pConditions);
}
if (res) {
res = addObject(jNode, jkPnodeSchema, dataBlockSchemaToJson, &phyNode->targetSchema);
}
if (res) {
res = addArray(jNode, jkPnodeChildren, phyNodeToJson, phyNode->pChildren);
}
if (res) {
res = addObject(jNode, phyNode->info.name, specificPhyNodeToJson, phyNode);
}
return res;
}
static bool phyNodeFromJson(const cJSON* json, void* obj) {
SPhyNode* node = (SPhyNode*) obj;
node->info.type = getNumber(json, jkPnodeType);
node->info.name = opTypeToOpName(node->info.type);
bool res = fromArray(json, jkPnodeTargets, exprInfoFromJson, &node->pTargets, sizeof(SExprInfo));
if (res) {
res = fromArray(json, jkPnodeConditions, exprInfoFromJson, &node->pConditions, sizeof(SExprInfo));
}
if (res) {
res = fromObject(json, jkPnodeSchema, dataBlockSchemaFromJson, &node->targetSchema, true);
}
if (res) {
res = fromPnodeArray(json, jkPnodeChildren, phyNodeFromJson, &node->pChildren);
}
if (res) {
res = fromObject(json, node->info.name, specificPhyNodeFromJson, node, true);
}
return res;
}
static const char* jkInserterNumOfTables = "NumOfTables";
static const char* jkInserterDataSize = "DataSize";
static bool inserterToJson(const void* obj, cJSON* json) {
const SDataInserter* inserter = (const SDataInserter*)obj;
bool res = cJSON_AddNumberToObject(json, jkInserterNumOfTables, inserter->numOfTables);
if (res) {
res = cJSON_AddNumberToObject(json, jkInserterDataSize, inserter->size);
}
// todo pData
return res;
}
static bool inserterFromJson(const cJSON* json, void* obj) {
SDataInserter* inserter = (SDataInserter*)obj;
inserter->numOfTables = getNumber(json, jkInserterNumOfTables);
inserter->size = getNumber(json, jkInserterDataSize);
// todo pData
}
static bool specificDataSinkToJson(const void* obj, cJSON* json) {
const SDataSink* dsink = (const SDataSink*)obj;
switch (dsink->info.type) {
case DSINK_Dispatch:
return true;
case DSINK_Insert:
return inserterToJson(obj, json);
default:
break;
}
return false;
}
static bool specificDataSinkFromJson(const cJSON* json, void* obj) {
SDataSink* dsink = (SDataSink*)obj;
switch (dsink->info.type) {
case DSINK_Dispatch:
return true;
case DSINK_Insert:
return inserterFromJson(json, obj);
default:
break;
}
return false;
}
static const char* jkDataSinkName = "Name";
static const char* jkDataSinkSchema = "Schema";
static bool dataSinkToJson(const void* obj, cJSON* json) {
const SDataSink* dsink = (const SDataSink*)obj;
bool res = cJSON_AddStringToObject(json, jkDataSinkName, dsink->info.name);
if (res) {
res = addObject(json, dsink->info.name, specificDataSinkToJson, dsink);
}
if (res) {
res = addObject(json, jkDataSinkSchema, dataBlockSchemaToJson, &dsink->schema);
}
return res;
}
static bool dataSinkFromJson(const cJSON* json, void* obj) {
SDataSink* dsink = (SDataSink*)obj;
dsink->info.name = getString(json, jkDataSinkName);
dsink->info.type = dsinkNameToDsinkType(dsink->info.name);
bool res = fromObject(json, jkDataSinkSchema, dataBlockSchemaFromJson, &dsink->schema, true);
if (res) {
res = fromObject(json, dsink->info.name, specificDataSinkFromJson, dsink, true);
}
return res;
}
static const char* jkIdQueryId = "QueryId";
static const char* jkIdTemplateId = "TemplateId";
static const char* jkIdSubplanId = "SubplanId";
static bool subplanIdToJson(const void* obj, cJSON* jId) {
const SSubplanId* id = (const SSubplanId*)obj;
char ids[40] = {0};
snprintf(ids, tListLen(ids), "%"PRIu64, id->queryId);
bool res = cJSON_AddStringToObject(jId, jkIdQueryId, ids);
if (res) {
res = cJSON_AddNumberToObject(jId, jkIdTemplateId, id->templateId);
}
if (res) {
res = cJSON_AddNumberToObject(jId, jkIdSubplanId, id->subplanId);
}
return res;
}
static bool subplanIdFromJson(const cJSON* json, void* obj) {
SSubplanId* id = (SSubplanId*)obj;
id->queryId = getBigintFromString(json, jkIdQueryId);
id->templateId = getNumber(json, jkIdTemplateId);
id->subplanId = getNumber(json, jkIdSubplanId);
return true;
}
static const char* jkSubplanId = "Id";
static const char* jkSubplanNode = "Node";
static const char* jkSubplanDataSink = "DataSink";
static cJSON* subplanToJson(const SSubplan* subplan) {
cJSON* jSubplan = cJSON_CreateObject();
if (NULL == jSubplan) {
return NULL;
}
// The 'type', 'level', 'execEpSet', 'pChildren' and 'pParents' fields do not need to be serialized.
bool res = addObject(jSubplan, jkSubplanId, subplanIdToJson, &subplan->id);
if (res) {
res = addObject(jSubplan, jkSubplanNode, phyNodeToJson, subplan->pNode);
}
if (res) {
res = addObject(jSubplan, jkSubplanDataSink, dataSinkToJson, subplan->pDataSink);
}
if (!res) {
cJSON_Delete(jSubplan);
return NULL;
}
return jSubplan;
}
static SSubplan* subplanFromJson(const cJSON* json) {
SSubplan* subplan = calloc(1, sizeof(SSubplan));
if (NULL == subplan) {
return NULL;
}
bool res = fromObject(json, jkSubplanId, subplanIdFromJson, &subplan->id, true);
if (res) {
res = fromPnode(json, jkSubplanNode, phyNodeFromJson, (void**)&subplan->pNode);
}
if (res) {
res = fromObjectWithAlloc(json, jkSubplanDataSink, dataSinkFromJson, (void**)&subplan->pDataSink, sizeof(SDataSink), false);
}
if (!res) {
qDestroySubplan(subplan);
return NULL;
}
return subplan;
}
int32_t subPlanToString(const SSubplan* subplan, char** str, int32_t* len) {
if (QUERY_TYPE_MODIFY == subplan->type) {
SDataInserter* insert = (SDataInserter*)(subplan->pDataSink);
*len = insert->size;
*str = insert->pData;
insert->pData = NULL;
return TSDB_CODE_SUCCESS;
}
cJSON* json = subplanToJson(subplan);
if (NULL == json) {
terrno = TSDB_CODE_TSC_OUT_OF_MEMORY;
return TSDB_CODE_FAILED;
}
*str = cJSON_Print(json);
cJSON_Delete(json);
*len = strlen(*str) + 1;
return TSDB_CODE_SUCCESS;
}
int32_t stringToSubplan(const char* str, SSubplan** subplan) {
cJSON* json = cJSON_Parse(str);
if (NULL == json) {
return TSDB_CODE_FAILED;
}
*subplan = subplanFromJson(json);
return (NULL == *subplan ? TSDB_CODE_FAILED : TSDB_CODE_SUCCESS);
}
cJSON* qDagToJson(const SQueryDag* pDag) {
cJSON* pRoot = cJSON_CreateObject();
if(pRoot == NULL) {
return NULL;
}
cJSON_AddNumberToObject(pRoot, "Number", pDag->numOfSubplans);
cJSON_AddNumberToObject(pRoot, "QueryId", pDag->queryId);
cJSON *pLevels = cJSON_CreateArray();
if(pLevels == NULL) {
cJSON_Delete(pRoot);
return NULL;
}
cJSON_AddItemToObject(pRoot, "Subplans", pLevels);
size_t level = taosArrayGetSize(pDag->pSubplans);
for(size_t i = 0; i < level; i++) {
const SArray* pSubplans = (const SArray*)taosArrayGetP(pDag->pSubplans, i);
size_t num = taosArrayGetSize(pSubplans);
cJSON* plansOneLevel = cJSON_CreateArray();
if(plansOneLevel == NULL) {
cJSON_Delete(pRoot);
return NULL;
}
cJSON_AddItemToArray(pLevels, plansOneLevel);
for(size_t j = 0; j < num; j++) {
cJSON* pSubplan = subplanToJson((const SSubplan*)taosArrayGetP(pSubplans, j));
if(pSubplan == NULL) {
cJSON_Delete(pRoot);
return NULL;
}
cJSON_AddItemToArray(plansOneLevel, pSubplan);
}
}
return pRoot;
}
char* qDagToString(const SQueryDag* pDag) {
cJSON* pRoot = qDagToJson(pDag);
return cJSON_Print(pRoot);
}
SQueryDag* qJsonToDag(const cJSON* pRoot) {
SQueryDag* pDag = malloc(sizeof(SQueryDag));
if(pDag == NULL) {
return NULL;
}
pDag->numOfSubplans = cJSON_GetNumberValue(cJSON_GetObjectItem(pRoot, "Number"));
pDag->queryId = cJSON_GetNumberValue(cJSON_GetObjectItem(pRoot, "QueryId"));
pDag->pSubplans = taosArrayInit(0, sizeof(SArray));
if (pDag->pSubplans == NULL) {
free(pDag);
return NULL;
}
cJSON* pLevels = cJSON_GetObjectItem(pRoot, "Subplans");
int level = cJSON_GetArraySize(pLevels);
for(int i = 0; i < level; i++) {
SArray* plansOneLevel = taosArrayInit(0, sizeof(void*));
if(plansOneLevel == NULL) {
for(int j = 0; j < i; j++) {
taosArrayDestroy(taosArrayGetP(pDag->pSubplans, j));
}
taosArrayDestroy(pDag->pSubplans);
free(pDag);
return NULL;
}
cJSON* pItem = cJSON_GetArrayItem(pLevels, i);
int sz = cJSON_GetArraySize(pItem);
for(int j = 0; j < sz; j++) {
cJSON* pSubplanJson = cJSON_GetArrayItem(pItem, j);
SSubplan* pSubplan = subplanFromJson(pSubplanJson);
taosArrayPush(plansOneLevel, &pSubplan);
}
taosArrayPush(pDag->pSubplans, plansOneLevel);
}
return pDag;
}
SQueryDag* qStringToDag(const char* pStr) {
cJSON* pRoot = cJSON_Parse(pStr);
return qJsonToDag(pRoot);
}
#endif
source/libs/planner/src/planner.c
浏览文件 @
cd7a0e55
...
@@ -15,8 +15,22 @@
...
@@ -15,8 +15,22 @@
#include "planner.h"
#include "planner.h"
int32_t
qCreateQueryPlan
(
SPlanContext
*
pCxt
,
SQueryPlan
**
pPlan
)
{
#include "plannerInt.h"
int32_t
optimize
(
SPlanContext
*
pCxt
,
SLogicNode
*
pLogicNode
)
{
return
TSDB_CODE_SUCCESS
;
}
int32_t
qCreateQueryPlan
(
SPlanContext
*
pCxt
,
SQueryPlan
**
pPlan
)
{
SLogicNode
*
pLogicNode
=
NULL
;
int32_t
code
=
createLogicPlan
(
pCxt
,
&
pLogicNode
);
if
(
TSDB_CODE_SUCCESS
==
code
)
{
code
=
optimize
(
pCxt
,
pLogicNode
);
}
if
(
TSDB_CODE_SUCCESS
==
code
)
{
code
=
buildPhysiPlan
(
pCxt
,
pLogicNode
,
pPlan
);
}
return
code
;
}
}
void
qSetSubplanExecutionNode
(
SSubplan
*
subplan
,
uint64_t
templateId
,
SDownstreamSource
*
pSource
)
{
void
qSetSubplanExecutionNode
(
SSubplan
*
subplan
,
uint64_t
templateId
,
SDownstreamSource
*
pSource
)
{
...
...
source/libs/planner/src/plannerImpl.c
已删除
100644 → 0
浏览文件 @
768e0593
/*
* 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 "plannerImpl.h"
#include "functionMgt.h"
#include "query.h"
#define CHECK_ALLOC(p, res) \
do { \
if (NULL == (p)) { \
pCxt->errCode = TSDB_CODE_OUT_OF_MEMORY; \
return (res); \
} \
} while (0)
#define CHECK_CODE(exec, res) \
do { \
int32_t code = (exec); \
if (TSDB_CODE_SUCCESS != code) { \
pCxt->errCode = code; \
return (res); \
} \
} while (0)
typedef
struct
SLogicPlanContext
{
int32_t
errCode
;
int32_t
planNodeId
;
}
SLogicPlanContext
;
static
SLogicNode
*
createQueryLogicNode
(
SLogicPlanContext
*
pCxt
,
SNode
*
pStmt
);
static
SLogicNode
*
createLogicNodeByTable
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
,
SNode
*
pTable
);
typedef
struct
SRewriteExprCxt
{
int32_t
errCode
;
SNodeList
*
pExprs
;
}
SRewriteExprCxt
;
static
EDealRes
doRewriteExpr
(
SNode
**
pNode
,
void
*
pContext
)
{
switch
(
nodeType
(
*
pNode
))
{
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
(
QUERY_NODE_GROUPING_SET
==
nodeType
(
pExpr
))
{
pExpr
=
nodesListGetNode
(((
SGroupingSetNode
*
)
pExpr
)
->
pParameterList
,
0
);
}
if
(
nodesEqualNode
(
pExpr
,
*
pNode
))
{
SColumnNode
*
pCol
=
(
SColumnNode
*
)
nodesMakeNode
(
QUERY_NODE_COLUMN
);
CHECK_ALLOC
(
pCol
,
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
;
}
return
DEAL_RES_CONTINUE
;
}
typedef
struct
SNameExprCxt
{
int32_t
planNodeId
;
int32_t
rewriteId
;
}
SNameExprCxt
;
static
EDealRes
doNameExpr
(
SNode
*
pNode
,
void
*
pContext
)
{
switch
(
nodeType
(
pNode
))
{
case
QUERY_NODE_OPERATOR
:
case
QUERY_NODE_LOGIC_CONDITION
:
case
QUERY_NODE_FUNCTION
:
{
SNameExprCxt
*
pCxt
=
(
SNameExprCxt
*
)
pContext
;
sprintf
(((
SExprNode
*
)
pNode
)
->
aliasName
,
"#expr_%d_%d"
,
pCxt
->
planNodeId
,
pCxt
->
rewriteId
++
);
return
DEAL_RES_IGNORE_CHILD
;
}
default:
break
;
}
return
DEAL_RES_CONTINUE
;
}
static
int32_t
rewriteExpr
(
int32_t
planNodeId
,
int32_t
rewriteId
,
SNodeList
*
pExprs
,
SSelectStmt
*
pSelect
,
ESqlClause
clause
)
{
SNameExprCxt
nameCxt
=
{
.
planNodeId
=
planNodeId
,
.
rewriteId
=
rewriteId
};
nodesWalkList
(
pExprs
,
doNameExpr
,
&
nameCxt
);
SRewriteExprCxt
cxt
=
{
.
errCode
=
TSDB_CODE_SUCCESS
,
.
pExprs
=
pExprs
};
nodesRewriteSelectStmt
(
pSelect
,
clause
,
doRewriteExpr
,
&
cxt
);
return
cxt
.
errCode
;
}
static
SLogicNode
*
pushLogicNode
(
SLogicPlanContext
*
pCxt
,
SLogicNode
*
pRoot
,
SLogicNode
*
pNode
)
{
if
(
TSDB_CODE_SUCCESS
!=
pCxt
->
errCode
)
{
goto
error
;
}
if
(
NULL
==
pRoot
)
{
return
pNode
;
}
if
(
NULL
==
pNode
)
{
return
pRoot
;
}
if
(
NULL
==
pNode
->
pChildren
)
{
pNode
->
pChildren
=
nodesMakeList
();
if
(
NULL
==
pNode
->
pChildren
)
{
goto
error
;
}
}
if
(
TSDB_CODE_SUCCESS
!=
nodesListAppend
(
pNode
->
pChildren
,
(
SNode
*
)
pRoot
))
{
goto
error
;
}
pRoot
->
pParent
=
pNode
;
return
pNode
;
error:
nodesDestroyNode
((
SNode
*
)
pNode
);
return
pRoot
;
}
static
SLogicNode
*
createScanLogicNode
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
,
SRealTableNode
*
pRealTable
)
{
SScanLogicNode
*
pScan
=
(
SScanLogicNode
*
)
nodesMakeNode
(
QUERY_NODE_LOGIC_PLAN_SCAN
);
CHECK_ALLOC
(
pScan
,
NULL
);
pScan
->
node
.
id
=
pCxt
->
planNodeId
++
;
pScan
->
pMeta
=
pRealTable
->
pMeta
;
// set columns to scan
SNodeList
*
pCols
=
NULL
;
CHECK_CODE
(
nodesCollectColumns
(
pSelect
,
SQL_CLAUSE_FROM
,
pRealTable
->
table
.
tableAlias
,
&
pCols
),
(
SLogicNode
*
)
pScan
);
if
(
NULL
!=
pCols
)
{
pScan
->
pScanCols
=
nodesCloneList
(
pCols
);
CHECK_ALLOC
(
pScan
->
pScanCols
,
(
SLogicNode
*
)
pScan
);
}
// set output
if
(
NULL
!=
pCols
)
{
pScan
->
node
.
pTargets
=
nodesCloneList
(
pCols
);
CHECK_ALLOC
(
pScan
->
node
.
pTargets
,
(
SLogicNode
*
)
pScan
);
}
pScan
->
scanType
=
SCAN_TYPE_TABLE
;
pScan
->
scanFlag
=
MAIN_SCAN
;
pScan
->
scanRange
=
TSWINDOW_INITIALIZER
;
return
(
SLogicNode
*
)
pScan
;
}
static
SLogicNode
*
createSubqueryLogicNode
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
,
STempTableNode
*
pTable
)
{
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
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
,
SJoinTableNode
*
pJoinTable
)
{
SJoinLogicNode
*
pJoin
=
(
SJoinLogicNode
*
)
nodesMakeNode
(
QUERY_NODE_LOGIC_PLAN_JOIN
);
CHECK_ALLOC
(
pJoin
,
NULL
);
pJoin
->
node
.
id
=
pCxt
->
planNodeId
++
;
pJoin
->
joinType
=
pJoinTable
->
joinType
;
// set left and right node
pJoin
->
node
.
pChildren
=
nodesMakeList
();
CHECK_ALLOC
(
pJoin
->
node
.
pChildren
,
(
SLogicNode
*
)
pJoin
);
SLogicNode
*
pLeft
=
createLogicNodeByTable
(
pCxt
,
pSelect
,
pJoinTable
->
pLeft
);
CHECK_ALLOC
(
pLeft
,
(
SLogicNode
*
)
pJoin
);
CHECK_CODE
(
nodesListAppend
(
pJoin
->
node
.
pChildren
,
(
SNode
*
)
pLeft
),
(
SLogicNode
*
)
pJoin
);
SLogicNode
*
pRight
=
createLogicNodeByTable
(
pCxt
,
pSelect
,
pJoinTable
->
pRight
);
CHECK_ALLOC
(
pRight
,
(
SLogicNode
*
)
pJoin
);
CHECK_CODE
(
nodesListAppend
(
pJoin
->
node
.
pChildren
,
(
SNode
*
)
pRight
),
(
SLogicNode
*
)
pJoin
);
// set on conditions
if
(
NULL
!=
pJoinTable
->
pOnCond
)
{
pJoin
->
pOnConditions
=
nodesCloneNode
(
pJoinTable
->
pOnCond
);
CHECK_ALLOC
(
pJoin
->
pOnConditions
,
(
SLogicNode
*
)
pJoin
);
}
// set the output
pJoin
->
node
.
pTargets
=
nodesCloneList
(
pLeft
->
pTargets
);
CHECK_ALLOC
(
pJoin
->
node
.
pTargets
,
(
SLogicNode
*
)
pJoin
);
SNodeList
*
pTargets
=
nodesCloneList
(
pRight
->
pTargets
);
CHECK_ALLOC
(
pTargets
,
(
SLogicNode
*
)
pJoin
);
nodesListAppendList
(
pJoin
->
node
.
pTargets
,
pTargets
);
return
(
SLogicNode
*
)
pJoin
;
}
static
SLogicNode
*
createLogicNodeByTable
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
,
SNode
*
pTable
)
{
switch
(
nodeType
(
pTable
))
{
case
QUERY_NODE_REAL_TABLE
:
return
createScanLogicNode
(
pCxt
,
pSelect
,
(
SRealTableNode
*
)
pTable
);
case
QUERY_NODE_TEMP_TABLE
:
return
createSubqueryLogicNode
(
pCxt
,
pSelect
,
(
STempTableNode
*
)
pTable
);
case
QUERY_NODE_JOIN_TABLE
:
return
createJoinLogicNode
(
pCxt
,
pSelect
,
(
SJoinTableNode
*
)
pTable
);
default:
break
;
}
return
NULL
;
}
typedef
struct
SCreateColumnCxt
{
int32_t
errCode
;
SNodeList
*
pList
;
}
SCreateColumnCxt
;
static
EDealRes
doCreateColumn
(
SNode
*
pNode
,
void
*
pContext
)
{
SCreateColumnCxt
*
pCxt
=
(
SCreateColumnCxt
*
)
pContext
;
switch
(
nodeType
(
pNode
))
{
case
QUERY_NODE_COLUMN
:
{
SNode
*
pCol
=
nodesCloneNode
(
pNode
);
CHECK_ALLOC
(
pCol
,
DEAL_RES_ERROR
);
CHECK_CODE
(
nodesListAppend
(
pCxt
->
pList
,
pCol
),
DEAL_RES_ERROR
);
return
DEAL_RES_IGNORE_CHILD
;
}
case
QUERY_NODE_OPERATOR
:
case
QUERY_NODE_LOGIC_CONDITION
:
case
QUERY_NODE_FUNCTION
:
{
SExprNode
*
pExpr
=
(
SExprNode
*
)
pNode
;
SColumnNode
*
pCol
=
(
SColumnNode
*
)
nodesMakeNode
(
QUERY_NODE_COLUMN
);
CHECK_ALLOC
(
pCol
,
DEAL_RES_ERROR
);
pCol
->
node
.
resType
=
pExpr
->
resType
;
strcpy
(
pCol
->
colName
,
pExpr
->
aliasName
);
CHECK_CODE
(
nodesListAppend
(
pCxt
->
pList
,
(
SNode
*
)
pCol
),
DEAL_RES_ERROR
);
return
DEAL_RES_IGNORE_CHILD
;
}
default:
break
;
}
return
DEAL_RES_CONTINUE
;
}
static
SNodeList
*
createColumnByRewriteExps
(
SLogicPlanContext
*
pCxt
,
SNodeList
*
pExprs
)
{
SCreateColumnCxt
cxt
=
{
.
errCode
=
TSDB_CODE_SUCCESS
,
.
pList
=
nodesMakeList
()
};
CHECK_ALLOC
(
cxt
.
pList
,
NULL
);
nodesWalkList
(
pExprs
,
doCreateColumn
,
&
cxt
);
if
(
TSDB_CODE_SUCCESS
!=
cxt
.
errCode
)
{
nodesDestroyList
(
cxt
.
pList
);
return
NULL
;
}
return
cxt
.
pList
;
}
static
SLogicNode
*
createAggLogicNode
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
)
{
SNodeList
*
pAggFuncs
=
NULL
;
CHECK_CODE
(
nodesCollectFuncs
(
pSelect
,
fmIsAggFunc
,
&
pAggFuncs
),
NULL
);
if
(
NULL
==
pAggFuncs
&&
NULL
==
pSelect
->
pGroupByList
)
{
return
NULL
;
}
SAggLogicNode
*
pAgg
=
(
SAggLogicNode
*
)
nodesMakeNode
(
QUERY_NODE_LOGIC_PLAN_AGG
);
CHECK_ALLOC
(
pAgg
,
NULL
);
pAgg
->
node
.
id
=
pCxt
->
planNodeId
++
;
// set grouyp keys, agg funcs and having conditions
if
(
NULL
!=
pSelect
->
pGroupByList
)
{
pAgg
->
pGroupKeys
=
nodesCloneList
(
pSelect
->
pGroupByList
);
CHECK_ALLOC
(
pAgg
->
pGroupKeys
,
(
SLogicNode
*
)
pAgg
);
}
if
(
NULL
!=
pAggFuncs
)
{
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
);
if
(
NULL
!=
pSelect
->
pHaving
)
{
pAgg
->
node
.
pConditions
=
nodesCloneNode
(
pSelect
->
pHaving
);
CHECK_ALLOC
(
pAgg
->
node
.
pConditions
,
(
SLogicNode
*
)
pAgg
);
}
// set the output
pAgg
->
node
.
pTargets
=
nodesMakeList
();
CHECK_ALLOC
(
pAgg
->
node
.
pTargets
,
(
SLogicNode
*
)
pAgg
);
if
(
NULL
!=
pAgg
->
pGroupKeys
)
{
SNodeList
*
pTargets
=
createColumnByRewriteExps
(
pCxt
,
pAgg
->
pGroupKeys
);
CHECK_ALLOC
(
pAgg
->
node
.
pTargets
,
(
SLogicNode
*
)
pAgg
);
nodesListAppendList
(
pAgg
->
node
.
pTargets
,
pTargets
);
}
if
(
NULL
!=
pAgg
->
pAggFuncs
)
{
SNodeList
*
pTargets
=
createColumnByRewriteExps
(
pCxt
,
pAgg
->
pAggFuncs
);
CHECK_ALLOC
(
pTargets
,
(
SLogicNode
*
)
pAgg
);
nodesListAppendList
(
pAgg
->
node
.
pTargets
,
pTargets
);
}
return
(
SLogicNode
*
)
pAgg
;
}
static
SNodeList
*
createColumnByProjections
(
SLogicPlanContext
*
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
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
)
{
SProjectLogicNode
*
pProject
=
(
SProjectLogicNode
*
)
nodesMakeNode
(
QUERY_NODE_LOGIC_PLAN_PROJECT
);
CHECK_ALLOC
(
pProject
,
NULL
);
pProject
->
node
.
id
=
pCxt
->
planNodeId
++
;
pProject
->
pProjections
=
nodesCloneList
(
pSelect
->
pProjectionList
);
pProject
->
node
.
pTargets
=
createColumnByProjections
(
pCxt
,
pSelect
->
pProjectionList
);
CHECK_ALLOC
(
pProject
->
node
.
pTargets
,
(
SLogicNode
*
)
pProject
);
return
(
SLogicNode
*
)
pProject
;
}
static
SLogicNode
*
createSelectLogicNode
(
SLogicPlanContext
*
pCxt
,
SSelectStmt
*
pSelect
)
{
SLogicNode
*
pRoot
=
createLogicNodeByTable
(
pCxt
,
pSelect
,
pSelect
->
pFromTable
);
if
(
TSDB_CODE_SUCCESS
==
pCxt
->
errCode
&&
NULL
!=
pSelect
->
pWhere
)
{
pRoot
->
pConditions
=
nodesCloneNode
(
pSelect
->
pWhere
);
CHECK_ALLOC
(
pRoot
->
pConditions
,
pRoot
);
}
if
(
TSDB_CODE_SUCCESS
==
pCxt
->
errCode
)
{
pRoot
=
pushLogicNode
(
pCxt
,
pRoot
,
createAggLogicNode
(
pCxt
,
pSelect
));
}
if
(
TSDB_CODE_SUCCESS
==
pCxt
->
errCode
)
{
pRoot
=
pushLogicNode
(
pCxt
,
pRoot
,
createProjectLogicNode
(
pCxt
,
pSelect
));
}
return
pRoot
;
}
static
SLogicNode
*
createQueryLogicNode
(
SLogicPlanContext
*
pCxt
,
SNode
*
pStmt
)
{
switch
(
nodeType
(
pStmt
))
{
case
QUERY_NODE_SELECT_STMT
:
return
createSelectLogicNode
(
pCxt
,
(
SSelectStmt
*
)
pStmt
);
default:
break
;
}
}
int32_t
createLogicPlan
(
SNode
*
pNode
,
SLogicNode
**
pLogicNode
)
{
SLogicPlanContext
cxt
=
{
.
errCode
=
TSDB_CODE_SUCCESS
,
.
planNodeId
=
1
};
SLogicNode
*
pRoot
=
createQueryLogicNode
(
&
cxt
,
pNode
);
if
(
TSDB_CODE_SUCCESS
!=
cxt
.
errCode
)
{
nodesDestroyNode
((
SNode
*
)
pRoot
);
return
cxt
.
errCode
;
}
*
pLogicNode
=
pRoot
;
return
TSDB_CODE_SUCCESS
;
}
int32_t
optimize
(
SLogicNode
*
pLogicNode
)
{
// todo
return
TSDB_CODE_SUCCESS
;
}
typedef
struct
SSubLogicPlan
{
SNode
*
pRoot
;
// SLogicNode
bool
haveSuperTable
;
bool
haveSystemTable
;
}
SSubLogicPlan
;
int32_t
splitLogicPlan
(
SSubLogicPlan
*
pLogicPlan
)
{
// todo
return
TSDB_CODE_SUCCESS
;
}
typedef
struct
SSlotIndex
{
int16_t
dataBlockId
;
int16_t
slotId
;
}
SSlotIndex
;
typedef
struct
SPhysiPlanContext
{
int32_t
errCode
;
int16_t
nextDataBlockId
;
SArray
*
pLocationHelper
;
}
SPhysiPlanContext
;
static
int32_t
getSlotKey
(
SNode
*
pNode
,
char
*
pKey
)
{
if
(
QUERY_NODE_COLUMN
==
nodeType
(
pNode
))
{
SColumnNode
*
pCol
=
(
SColumnNode
*
)
pNode
;
if
(
'\0'
==
pCol
->
tableAlias
[
0
])
{
return
sprintf
(
pKey
,
"%s"
,
pCol
->
colName
);
}
return
sprintf
(
pKey
,
"%s.%s"
,
pCol
->
tableAlias
,
pCol
->
colName
);
}
return
sprintf
(
pKey
,
"%s"
,
((
SExprNode
*
)
pNode
)
->
aliasName
);
}
static
SNode
*
createSlotDesc
(
SPhysiPlanContext
*
pCxt
,
const
SNode
*
pNode
,
int16_t
slotId
)
{
SSlotDescNode
*
pSlot
=
(
SSlotDescNode
*
)
nodesMakeNode
(
QUERY_NODE_SLOT_DESC
);
CHECK_ALLOC
(
pSlot
,
NULL
);
pSlot
->
slotId
=
slotId
;
pSlot
->
dataType
=
((
SExprNode
*
)
pNode
)
->
resType
;
pSlot
->
reserve
=
false
;
pSlot
->
output
=
false
;
return
(
SNode
*
)
pSlot
;
}
static
SNode
*
createTarget
(
SNode
*
pNode
,
int16_t
dataBlockId
,
int16_t
slotId
)
{
STargetNode
*
pTarget
=
(
STargetNode
*
)
nodesMakeNode
(
QUERY_NODE_TARGET
);
if
(
NULL
==
pTarget
)
{
return
NULL
;
}
pTarget
->
dataBlockId
=
dataBlockId
;
pTarget
->
slotId
=
slotId
;
pTarget
->
pExpr
=
pNode
;
return
(
SNode
*
)
pTarget
;
}
static
int32_t
addDataBlockDesc
(
SPhysiPlanContext
*
pCxt
,
SNodeList
*
pList
,
SDataBlockDescNode
*
pDataBlockDesc
)
{
SHashObj
*
pHash
=
NULL
;
if
(
NULL
==
pDataBlockDesc
->
pSlots
)
{
pDataBlockDesc
->
pSlots
=
nodesMakeList
();
CHECK_ALLOC
(
pDataBlockDesc
->
pSlots
,
TSDB_CODE_OUT_OF_MEMORY
);
pHash
=
taosHashInit
(
LIST_LENGTH
(
pList
),
taosGetDefaultHashFunction
(
TSDB_DATA_TYPE_BINARY
),
true
,
HASH_NO_LOCK
);
CHECK_ALLOC
(
pHash
,
TSDB_CODE_OUT_OF_MEMORY
);
if
(
NULL
==
taosArrayInsert
(
pCxt
->
pLocationHelper
,
pDataBlockDesc
->
dataBlockId
,
&
pHash
))
{
taosHashCleanup
(
pHash
);
return
TSDB_CODE_OUT_OF_MEMORY
;
}
}
else
{
pHash
=
taosArrayGetP
(
pCxt
->
pLocationHelper
,
pDataBlockDesc
->
dataBlockId
);
}
SNode
*
pNode
=
NULL
;
int16_t
slotId
=
taosHashGetSize
(
pHash
);
FOREACH
(
pNode
,
pList
)
{
SNode
*
pSlot
=
createSlotDesc
(
pCxt
,
pNode
,
slotId
);
CHECK_ALLOC
(
pSlot
,
TSDB_CODE_OUT_OF_MEMORY
);
if
(
TSDB_CODE_SUCCESS
!=
nodesListAppend
(
pDataBlockDesc
->
pSlots
,
(
SNode
*
)
pSlot
))
{
nodesDestroyNode
(
pSlot
);
return
TSDB_CODE_OUT_OF_MEMORY
;
}
SSlotIndex
index
=
{
.
dataBlockId
=
pDataBlockDesc
->
dataBlockId
,
.
slotId
=
slotId
};
char
name
[
TSDB_TABLE_NAME_LEN
+
TSDB_COL_NAME_LEN
];
int32_t
len
=
getSlotKey
(
pNode
,
name
);
CHECK_CODE
(
taosHashPut
(
pHash
,
name
,
len
,
&
index
,
sizeof
(
SSlotIndex
)),
TSDB_CODE_OUT_OF_MEMORY
);
SNode
*
pTarget
=
createTarget
(
pNode
,
pDataBlockDesc
->
dataBlockId
,
slotId
);
CHECK_ALLOC
(
pTarget
,
TSDB_CODE_OUT_OF_MEMORY
);
REPLACE_NODE
(
pTarget
);
++
slotId
;
}
return
TSDB_CODE_SUCCESS
;
}
typedef
struct
SSetSlotIdCxt
{
int32_t
errCode
;
SHashObj
*
pLeftHash
;
SHashObj
*
pRightHash
;
}
SSetSlotIdCxt
;
static
EDealRes
doSetSlotId
(
SNode
*
pNode
,
void
*
pContext
)
{
if
(
QUERY_NODE_COLUMN
==
nodeType
(
pNode
)
&&
0
!=
strcmp
(((
SColumnNode
*
)
pNode
)
->
colName
,
"*"
))
{
SSetSlotIdCxt
*
pCxt
=
(
SSetSlotIdCxt
*
)
pContext
;
char
name
[
TSDB_TABLE_NAME_LEN
+
TSDB_COL_NAME_LEN
];
int32_t
len
=
getSlotKey
(
pNode
,
name
);
SSlotIndex
*
pIndex
=
taosHashGet
(
pCxt
->
pLeftHash
,
name
,
len
);
if
(
NULL
==
pIndex
)
{
pIndex
=
taosHashGet
(
pCxt
->
pRightHash
,
name
,
len
);
}
// pIndex is definitely not NULL, otherwise it is a bug
((
SColumnNode
*
)
pNode
)
->
dataBlockId
=
pIndex
->
dataBlockId
;
((
SColumnNode
*
)
pNode
)
->
slotId
=
pIndex
->
slotId
;
CHECK_ALLOC
(
pNode
,
DEAL_RES_ERROR
);
return
DEAL_RES_IGNORE_CHILD
;
}
return
DEAL_RES_CONTINUE
;
}
static
SNode
*
setNodeSlotId
(
SPhysiPlanContext
*
pCxt
,
int16_t
leftDataBlockId
,
int16_t
rightDataBlockId
,
SNode
*
pNode
)
{
SNode
*
pRes
=
nodesCloneNode
(
pNode
);
CHECK_ALLOC
(
pRes
,
NULL
);
SSetSlotIdCxt
cxt
=
{
.
errCode
=
TSDB_CODE_SUCCESS
,
.
pLeftHash
=
taosArrayGetP
(
pCxt
->
pLocationHelper
,
leftDataBlockId
),
.
pRightHash
=
(
rightDataBlockId
<
0
?
NULL
:
taosArrayGetP
(
pCxt
->
pLocationHelper
,
rightDataBlockId
))
};
nodesWalkNode
(
pRes
,
doSetSlotId
,
&
cxt
);
if
(
TSDB_CODE_SUCCESS
!=
cxt
.
errCode
)
{
nodesDestroyNode
(
pRes
);
return
NULL
;
}
return
pRes
;
}
static
SNodeList
*
setListSlotId
(
SPhysiPlanContext
*
pCxt
,
int16_t
leftDataBlockId
,
int16_t
rightDataBlockId
,
SNodeList
*
pList
)
{
SNodeList
*
pRes
=
nodesCloneList
(
pList
);
CHECK_ALLOC
(
pRes
,
NULL
);
SSetSlotIdCxt
cxt
=
{
.
errCode
=
TSDB_CODE_SUCCESS
,
.
pLeftHash
=
taosArrayGetP
(
pCxt
->
pLocationHelper
,
leftDataBlockId
),
.
pRightHash
=
(
rightDataBlockId
<
0
?
NULL
:
taosArrayGetP
(
pCxt
->
pLocationHelper
,
rightDataBlockId
))
};
nodesWalkList
(
pRes
,
doSetSlotId
,
&
cxt
);
if
(
TSDB_CODE_SUCCESS
!=
cxt
.
errCode
)
{
nodesDestroyList
(
pRes
);
return
NULL
;
}
return
pRes
;
}
static
SPhysiNode
*
makePhysiNode
(
SPhysiPlanContext
*
pCxt
,
ENodeType
type
)
{
SPhysiNode
*
pPhysiNode
=
(
SPhysiNode
*
)
nodesMakeNode
(
type
);
if
(
NULL
==
pPhysiNode
)
{
return
NULL
;
}
pPhysiNode
->
outputDataBlockDesc
.
dataBlockId
=
pCxt
->
nextDataBlockId
++
;
pPhysiNode
->
outputDataBlockDesc
.
type
=
QUERY_NODE_DATABLOCK_DESC
;
return
pPhysiNode
;
}
static
int32_t
setConditionsSlotId
(
SPhysiPlanContext
*
pCxt
,
const
SLogicNode
*
pLogicNode
,
SPhysiNode
*
pPhysiNode
)
{
if
(
NULL
!=
pLogicNode
->
pConditions
)
{
pPhysiNode
->
pConditions
=
setNodeSlotId
(
pCxt
,
pPhysiNode
->
outputDataBlockDesc
.
dataBlockId
,
-
1
,
pLogicNode
->
pConditions
);
CHECK_ALLOC
(
pPhysiNode
->
pConditions
,
TSDB_CODE_OUT_OF_MEMORY
);
}
return
TSDB_CODE_SUCCESS
;
}
static
int32_t
setSlotOutput
(
SPhysiPlanContext
*
pCxt
,
SNodeList
*
pTargets
,
SDataBlockDescNode
*
pDataBlockDesc
)
{
SHashObj
*
pHash
=
taosArrayGetP
(
pCxt
->
pLocationHelper
,
pDataBlockDesc
->
dataBlockId
);
char
name
[
TSDB_TABLE_NAME_LEN
+
TSDB_COL_NAME_LEN
];
SNode
*
pNode
;
FOREACH
(
pNode
,
pTargets
)
{
int32_t
len
=
getSlotKey
(
pNode
,
name
);
SSlotIndex
*
pIndex
=
taosHashGet
(
pHash
,
name
,
len
);
((
SSlotDescNode
*
)
nodesListGetNode
(
pDataBlockDesc
->
pSlots
,
pIndex
->
slotId
))
->
output
=
true
;
}
return
TSDB_CODE_SUCCESS
;
}
static
int32_t
initScanPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SScanLogicNode
*
pScanLogicNode
,
SScanPhysiNode
*
pScanPhysiNode
)
{
if
(
NULL
!=
pScanLogicNode
->
pScanCols
)
{
pScanPhysiNode
->
pScanCols
=
nodesCloneList
(
pScanLogicNode
->
pScanCols
);
CHECK_ALLOC
(
pScanPhysiNode
->
pScanCols
,
TSDB_CODE_OUT_OF_MEMORY
);
}
// Data block describe also needs to be set without scanning column, such as SELECT COUNT(*) FROM t
CHECK_CODE
(
addDataBlockDesc
(
pCxt
,
pScanPhysiNode
->
pScanCols
,
&
pScanPhysiNode
->
node
.
outputDataBlockDesc
),
TSDB_CODE_OUT_OF_MEMORY
);
CHECK_CODE
(
setConditionsSlotId
(
pCxt
,
(
const
SLogicNode
*
)
pScanLogicNode
,
(
SPhysiNode
*
)
pScanPhysiNode
),
TSDB_CODE_OUT_OF_MEMORY
);
CHECK_CODE
(
setSlotOutput
(
pCxt
,
pScanLogicNode
->
node
.
pTargets
,
&
pScanPhysiNode
->
node
.
outputDataBlockDesc
),
TSDB_CODE_OUT_OF_MEMORY
);
pScanPhysiNode
->
uid
=
pScanLogicNode
->
pMeta
->
uid
;
pScanPhysiNode
->
tableType
=
pScanLogicNode
->
pMeta
->
tableType
;
pScanPhysiNode
->
order
=
TSDB_ORDER_ASC
;
pScanPhysiNode
->
count
=
1
;
pScanPhysiNode
->
reverse
=
0
;
return
TSDB_CODE_SUCCESS
;
}
static
SPhysiNode
*
createTagScanPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SScanLogicNode
*
pScanLogicNode
)
{
STagScanPhysiNode
*
pTagScan
=
(
STagScanPhysiNode
*
)
makePhysiNode
(
pCxt
,
QUERY_NODE_PHYSICAL_PLAN_TAG_SCAN
);
CHECK_ALLOC
(
pTagScan
,
NULL
);
CHECK_CODE
(
initScanPhysiNode
(
pCxt
,
pScanLogicNode
,
(
SScanPhysiNode
*
)
pTagScan
),
(
SPhysiNode
*
)
pTagScan
);
return
(
SPhysiNode
*
)
pTagScan
;
}
static
SPhysiNode
*
createTableScanPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SScanLogicNode
*
pScanLogicNode
)
{
STableScanPhysiNode
*
pTableScan
=
(
STableScanPhysiNode
*
)
makePhysiNode
(
pCxt
,
QUERY_NODE_PHYSICAL_PLAN_TABLE_SCAN
);
CHECK_ALLOC
(
pTableScan
,
NULL
);
CHECK_CODE
(
initScanPhysiNode
(
pCxt
,
pScanLogicNode
,
(
SScanPhysiNode
*
)
pTableScan
),
(
SPhysiNode
*
)
pTableScan
);
pTableScan
->
scanFlag
=
pScanLogicNode
->
scanFlag
;
pTableScan
->
scanRange
=
pScanLogicNode
->
scanRange
;
return
(
SPhysiNode
*
)
pTableScan
;
}
static
SPhysiNode
*
createScanPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SScanLogicNode
*
pScanLogicNode
)
{
switch
(
pScanLogicNode
->
scanType
)
{
case
SCAN_TYPE_TAG
:
return
createTagScanPhysiNode
(
pCxt
,
pScanLogicNode
);
case
SCAN_TYPE_TABLE
:
return
createTableScanPhysiNode
(
pCxt
,
pScanLogicNode
);
case
SCAN_TYPE_STABLE
:
case
SCAN_TYPE_STREAM
:
break
;
default:
break
;
}
return
NULL
;
}
static
SNodeList
*
createJoinOutputCols
(
SPhysiPlanContext
*
pCxt
,
SDataBlockDescNode
*
pLeftDesc
,
SDataBlockDescNode
*
pRightDesc
)
{
SNodeList
*
pCols
=
nodesMakeList
();
CHECK_ALLOC
(
pCols
,
NULL
);
SNode
*
pNode
;
FOREACH
(
pNode
,
pLeftDesc
->
pSlots
)
{
SSlotDescNode
*
pSlot
=
(
SSlotDescNode
*
)
pNode
;
SColumnNode
*
pCol
=
(
SColumnNode
*
)
nodesMakeNode
(
QUERY_NODE_COLUMN
);
if
(
NULL
==
pCol
)
{
goto
error
;
}
pCol
->
node
.
resType
=
pSlot
->
dataType
;
pCol
->
dataBlockId
=
pLeftDesc
->
dataBlockId
;
pCol
->
slotId
=
pSlot
->
slotId
;
pCol
->
colId
=
-
1
;
if
(
TSDB_CODE_SUCCESS
!=
nodesListAppend
(
pCols
,
(
SNode
*
)
pCol
))
{
goto
error
;
}
}
FOREACH
(
pNode
,
pRightDesc
->
pSlots
)
{
SSlotDescNode
*
pSlot
=
(
SSlotDescNode
*
)
pNode
;
SColumnNode
*
pCol
=
(
SColumnNode
*
)
nodesMakeNode
(
QUERY_NODE_COLUMN
);
if
(
NULL
==
pCol
)
{
goto
error
;
}
pCol
->
node
.
resType
=
pSlot
->
dataType
;
pCol
->
dataBlockId
=
pRightDesc
->
dataBlockId
;
pCol
->
slotId
=
pSlot
->
slotId
;
pCol
->
colId
=
-
1
;
if
(
TSDB_CODE_SUCCESS
!=
nodesListAppend
(
pCols
,
(
SNode
*
)
pCol
))
{
goto
error
;
}
}
return
pCols
;
error:
nodesDestroyList
(
pCols
);
return
NULL
;
}
static
SPhysiNode
*
createJoinPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SNodeList
*
pChildren
,
SJoinLogicNode
*
pJoinLogicNode
)
{
SJoinPhysiNode
*
pJoin
=
(
SJoinPhysiNode
*
)
makePhysiNode
(
pCxt
,
QUERY_NODE_PHYSICAL_PLAN_JOIN
);
CHECK_ALLOC
(
pJoin
,
NULL
);
SDataBlockDescNode
*
pLeftDesc
=
&
((
SPhysiNode
*
)
nodesListGetNode
(
pChildren
,
0
))
->
outputDataBlockDesc
;
SDataBlockDescNode
*
pRightDesc
=
&
((
SPhysiNode
*
)
nodesListGetNode
(
pChildren
,
1
))
->
outputDataBlockDesc
;
pJoin
->
pOnConditions
=
setNodeSlotId
(
pCxt
,
pLeftDesc
->
dataBlockId
,
pRightDesc
->
dataBlockId
,
pJoinLogicNode
->
pOnConditions
);
CHECK_ALLOC
(
pJoin
->
pOnConditions
,
(
SPhysiNode
*
)
pJoin
);
pJoin
->
pTargets
=
createJoinOutputCols
(
pCxt
,
pLeftDesc
,
pRightDesc
);
CHECK_ALLOC
(
pJoin
->
pTargets
,
(
SPhysiNode
*
)
pJoin
);
CHECK_CODE
(
addDataBlockDesc
(
pCxt
,
pJoin
->
pTargets
,
&
pJoin
->
node
.
outputDataBlockDesc
),
(
SPhysiNode
*
)
pJoin
);
CHECK_CODE
(
setConditionsSlotId
(
pCxt
,
(
const
SLogicNode
*
)
pJoinLogicNode
,
(
SPhysiNode
*
)
pJoin
),
(
SPhysiNode
*
)
pJoin
);
CHECK_CODE
(
setSlotOutput
(
pCxt
,
pJoinLogicNode
->
node
.
pTargets
,
&
pJoin
->
node
.
outputDataBlockDesc
),
(
SPhysiNode
*
)
pJoin
);
return
(
SPhysiNode
*
)
pJoin
;
}
typedef
struct
SRewritePrecalcExprsCxt
{
int32_t
errCode
;
int32_t
planNodeId
;
int32_t
rewriteId
;
SNodeList
*
pPrecalcExprs
;
}
SRewritePrecalcExprsCxt
;
static
EDealRes
collectAndRewrite
(
SRewritePrecalcExprsCxt
*
pCxt
,
SNode
**
pNode
)
{
SNode
*
pExpr
=
nodesCloneNode
(
*
pNode
);
CHECK_ALLOC
(
pExpr
,
DEAL_RES_ERROR
);
if
(
nodesListAppend
(
pCxt
->
pPrecalcExprs
,
pExpr
))
{
nodesDestroyNode
(
pExpr
);
return
DEAL_RES_ERROR
;
}
SColumnNode
*
pCol
=
(
SColumnNode
*
)
nodesMakeNode
(
QUERY_NODE_COLUMN
);
if
(
NULL
==
pCol
)
{
nodesDestroyNode
(
pExpr
);
return
DEAL_RES_ERROR
;
}
SExprNode
*
pRewrittenExpr
=
(
SExprNode
*
)
pExpr
;
pCol
->
node
.
resType
=
pRewrittenExpr
->
resType
;
if
(
'\0'
!=
pRewrittenExpr
->
aliasName
[
0
])
{
strcpy
(
pCol
->
colName
,
pRewrittenExpr
->
aliasName
);
}
else
{
snprintf
(
pRewrittenExpr
->
aliasName
,
sizeof
(
pRewrittenExpr
->
aliasName
),
"#expr_%d_%d"
,
pCxt
->
planNodeId
,
pCxt
->
rewriteId
);
strcpy
(
pCol
->
colName
,
pRewrittenExpr
->
aliasName
);
}
nodesDestroyNode
(
*
pNode
);
*
pNode
=
(
SNode
*
)
pCol
;
return
DEAL_RES_IGNORE_CHILD
;
}
static
EDealRes
doRewritePrecalcExprs
(
SNode
**
pNode
,
void
*
pContext
)
{
SRewritePrecalcExprsCxt
*
pCxt
=
(
SRewritePrecalcExprsCxt
*
)
pContext
;
switch
(
nodeType
(
*
pNode
))
{
case
QUERY_NODE_OPERATOR
:
case
QUERY_NODE_LOGIC_CONDITION
:
{
return
collectAndRewrite
(
pContext
,
pNode
);
}
case
QUERY_NODE_FUNCTION
:
{
if
(
!
fmIsAggFunc
(((
SFunctionNode
*
)(
*
pNode
))
->
funcId
))
{
return
collectAndRewrite
(
pContext
,
pNode
);
}
}
default:
break
;
}
return
DEAL_RES_CONTINUE
;
}
static
int32_t
rewritePrecalcExprs
(
SPhysiPlanContext
*
pCxt
,
SNodeList
*
pList
,
SNodeList
**
pPrecalcExprs
,
SNodeList
**
pRewrittenList
)
{
if
(
NULL
==
pList
)
{
return
TSDB_CODE_SUCCESS
;
}
if
(
NULL
==
*
pPrecalcExprs
)
{
*
pPrecalcExprs
=
nodesMakeList
();
CHECK_ALLOC
(
*
pPrecalcExprs
,
TSDB_CODE_OUT_OF_MEMORY
);
}
if
(
NULL
==
*
pRewrittenList
)
{
*
pRewrittenList
=
nodesMakeList
();
CHECK_ALLOC
(
*
pRewrittenList
,
TSDB_CODE_OUT_OF_MEMORY
);
}
SNode
*
pNode
=
NULL
;
FOREACH
(
pNode
,
pList
)
{
SNode
*
pNew
=
NULL
;
if
(
QUERY_NODE_GROUPING_SET
==
nodeType
(
pNode
))
{
pNew
=
nodesCloneNode
(
nodesListGetNode
(((
SGroupingSetNode
*
)
pNode
)
->
pParameterList
,
0
));
}
else
{
pNew
=
nodesCloneNode
(
pNode
);
}
CHECK_ALLOC
(
pNew
,
TSDB_CODE_OUT_OF_MEMORY
);
CHECK_CODE
(
nodesListAppend
(
*
pRewrittenList
,
pNew
),
TSDB_CODE_OUT_OF_MEMORY
);
}
SRewritePrecalcExprsCxt
cxt
=
{
.
errCode
=
TSDB_CODE_SUCCESS
,
.
pPrecalcExprs
=
*
pPrecalcExprs
};
nodesRewriteList
(
*
pRewrittenList
,
doRewritePrecalcExprs
,
&
cxt
);
if
(
0
==
LIST_LENGTH
(
cxt
.
pPrecalcExprs
))
{
nodesDestroyList
(
cxt
.
pPrecalcExprs
);
*
pPrecalcExprs
=
NULL
;
}
return
cxt
.
errCode
;
}
static
SPhysiNode
*
createAggPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SNodeList
*
pChildren
,
SAggLogicNode
*
pAggLogicNode
)
{
SAggPhysiNode
*
pAgg
=
(
SAggPhysiNode
*
)
makePhysiNode
(
pCxt
,
QUERY_NODE_PHYSICAL_PLAN_AGG
);
CHECK_ALLOC
(
pAgg
,
NULL
);
SNodeList
*
pPrecalcExprs
=
NULL
;
SNodeList
*
pGroupKeys
=
NULL
;
SNodeList
*
pAggFuncs
=
NULL
;
CHECK_CODE
(
rewritePrecalcExprs
(
pCxt
,
pAggLogicNode
->
pGroupKeys
,
&
pPrecalcExprs
,
&
pGroupKeys
),
(
SPhysiNode
*
)
pAgg
);
CHECK_CODE
(
rewritePrecalcExprs
(
pCxt
,
pAggLogicNode
->
pAggFuncs
,
&
pPrecalcExprs
,
&
pAggFuncs
),
(
SPhysiNode
*
)
pAgg
);
SDataBlockDescNode
*
pChildTupe
=
&
(((
SPhysiNode
*
)
nodesListGetNode
(
pChildren
,
0
))
->
outputDataBlockDesc
);
// push down expression to outputDataBlockDesc of child node
if
(
NULL
!=
pPrecalcExprs
)
{
pAgg
->
pExprs
=
setListSlotId
(
pCxt
,
pChildTupe
->
dataBlockId
,
-
1
,
pPrecalcExprs
);
CHECK_ALLOC
(
pAgg
->
pExprs
,
(
SPhysiNode
*
)
pAgg
);
CHECK_CODE
(
addDataBlockDesc
(
pCxt
,
pAgg
->
pExprs
,
pChildTupe
),
(
SPhysiNode
*
)
pAgg
);
}
if
(
NULL
!=
pGroupKeys
)
{
pAgg
->
pGroupKeys
=
setListSlotId
(
pCxt
,
pChildTupe
->
dataBlockId
,
-
1
,
pGroupKeys
);
CHECK_ALLOC
(
pAgg
->
pGroupKeys
,
(
SPhysiNode
*
)
pAgg
);
CHECK_CODE
(
addDataBlockDesc
(
pCxt
,
pAgg
->
pGroupKeys
,
&
pAgg
->
node
.
outputDataBlockDesc
),
(
SPhysiNode
*
)
pAgg
);
}
if
(
NULL
!=
pAggFuncs
)
{
pAgg
->
pAggFuncs
=
setListSlotId
(
pCxt
,
pChildTupe
->
dataBlockId
,
-
1
,
pAggFuncs
);
CHECK_ALLOC
(
pAgg
->
pAggFuncs
,
(
SPhysiNode
*
)
pAgg
);
CHECK_CODE
(
addDataBlockDesc
(
pCxt
,
pAgg
->
pAggFuncs
,
&
pAgg
->
node
.
outputDataBlockDesc
),
(
SPhysiNode
*
)
pAgg
);
}
CHECK_CODE
(
setConditionsSlotId
(
pCxt
,
(
const
SLogicNode
*
)
pAggLogicNode
,
(
SPhysiNode
*
)
pAgg
),
(
SPhysiNode
*
)
pAgg
);
CHECK_CODE
(
setSlotOutput
(
pCxt
,
pAggLogicNode
->
node
.
pTargets
,
&
pAgg
->
node
.
outputDataBlockDesc
),
(
SPhysiNode
*
)
pAgg
);
return
(
SPhysiNode
*
)
pAgg
;
}
static
SPhysiNode
*
createProjectPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SNodeList
*
pChildren
,
SProjectLogicNode
*
pProjectLogicNode
)
{
SProjectPhysiNode
*
pProject
=
(
SProjectPhysiNode
*
)
makePhysiNode
(
pCxt
,
QUERY_NODE_PHYSICAL_PLAN_PROJECT
);
CHECK_ALLOC
(
pProject
,
NULL
);
pProject
->
pProjections
=
setListSlotId
(
pCxt
,
((
SPhysiNode
*
)
nodesListGetNode
(
pChildren
,
0
))
->
outputDataBlockDesc
.
dataBlockId
,
-
1
,
pProjectLogicNode
->
pProjections
);
CHECK_ALLOC
(
pProject
->
pProjections
,
(
SPhysiNode
*
)
pProject
);
CHECK_CODE
(
addDataBlockDesc
(
pCxt
,
pProject
->
pProjections
,
&
pProject
->
node
.
outputDataBlockDesc
),
(
SPhysiNode
*
)
pProject
);
CHECK_CODE
(
setConditionsSlotId
(
pCxt
,
(
const
SLogicNode
*
)
pProjectLogicNode
,
(
SPhysiNode
*
)
pProject
),
(
SPhysiNode
*
)
pProject
);
return
(
SPhysiNode
*
)
pProject
;
}
static
SPhysiNode
*
createPhysiNode
(
SPhysiPlanContext
*
pCxt
,
SLogicNode
*
pLogicPlan
)
{
SNodeList
*
pChildren
=
nodesMakeList
();
CHECK_ALLOC
(
pChildren
,
NULL
);
SNode
*
pLogicChild
;
FOREACH
(
pLogicChild
,
pLogicPlan
->
pChildren
)
{
SNode
*
pChildPhyNode
=
(
SNode
*
)
createPhysiNode
(
pCxt
,
(
SLogicNode
*
)
pLogicChild
);
if
(
TSDB_CODE_SUCCESS
!=
nodesListAppend
(
pChildren
,
pChildPhyNode
))
{
pCxt
->
errCode
=
TSDB_CODE_OUT_OF_MEMORY
;
nodesDestroyList
(
pChildren
);
return
NULL
;
}
}
SPhysiNode
*
pPhyNode
=
NULL
;
switch
(
nodeType
(
pLogicPlan
))
{
case
QUERY_NODE_LOGIC_PLAN_SCAN
:
pPhyNode
=
createScanPhysiNode
(
pCxt
,
(
SScanLogicNode
*
)
pLogicPlan
);
break
;
case
QUERY_NODE_LOGIC_PLAN_JOIN
:
pPhyNode
=
createJoinPhysiNode
(
pCxt
,
pChildren
,
(
SJoinLogicNode
*
)
pLogicPlan
);
break
;
case
QUERY_NODE_LOGIC_PLAN_AGG
:
pPhyNode
=
createAggPhysiNode
(
pCxt
,
pChildren
,
(
SAggLogicNode
*
)
pLogicPlan
);
break
;
case
QUERY_NODE_LOGIC_PLAN_PROJECT
:
pPhyNode
=
createProjectPhysiNode
(
pCxt
,
pChildren
,
(
SProjectLogicNode
*
)
pLogicPlan
);
break
;
default:
break
;
}
pPhyNode
->
pChildren
=
pChildren
;
SNode
*
pChild
;
FOREACH
(
pChild
,
pPhyNode
->
pChildren
)
{
((
SPhysiNode
*
)
pChild
)
->
pParent
=
pPhyNode
;
}
return
pPhyNode
;
}
int32_t
createPhysiPlan
(
SLogicNode
*
pLogicNode
,
SPhysiNode
**
pPhyNode
)
{
SPhysiPlanContext
cxt
=
{
.
errCode
=
TSDB_CODE_SUCCESS
,
.
nextDataBlockId
=
0
,
.
pLocationHelper
=
taosArrayInit
(
32
,
POINTER_BYTES
)
};
if
(
NULL
==
cxt
.
pLocationHelper
)
{
return
TSDB_CODE_OUT_OF_MEMORY
;
}
*
pPhyNode
=
createPhysiNode
(
&
cxt
,
pLogicNode
);
return
cxt
.
errCode
;
}
int32_t
buildPhysiPlan
(
SLogicNode
*
pLogicNode
,
SPhysiNode
**
pPhyNode
)
{
// split
// scale out
// maping
// create
return
TSDB_CODE_SUCCESS
;
}
source/libs/planner/test/phyPlanTests.cpp
已删除
100644 → 0
浏览文件 @
768e0593
/*
* 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/>.
*/
#if 0
#include <gtest/gtest.h>
#include "plannerInt.h"
#include "mockCatalogService.h"
using namespace std;
using namespace testing;
void* myCalloc(size_t nmemb, size_t size) {
if (void* p = calloc(nmemb, size)) {
return p;
}
throw bad_alloc();
}
class PhyPlanTest : public Test {
protected:
void pushAgg(int32_t aggOp) {
unique_ptr<SQueryPlanNode> agg((SQueryPlanNode*)myCalloc(1, sizeof(SQueryPlanNode)));
agg->info.type = aggOp;
agg->pExpr = taosArrayInit(TARRAY_MIN_SIZE, POINTER_BYTES);
unique_ptr<SExprInfo> expr((SExprInfo*)myCalloc(1, sizeof(SExprInfo)));
expr->base.resSchema.type = TSDB_DATA_TYPE_INT;
expr->base.resSchema.bytes = tDataTypes[TSDB_DATA_TYPE_INT].bytes;
expr->pExpr = (tExprNode*)myCalloc(1, sizeof(tExprNode));
expr->pExpr->nodeType = TEXPR_FUNCTION_NODE;
strcpy(expr->pExpr->_function.functionName, "Count");
SExprInfo* item = expr.release();
taosArrayPush(agg->pExpr, &item);
pushNode(agg.release());
}
void pushScan(const string& db, const string& table, int32_t scanOp) {
shared_ptr<MockTableMeta> meta = mockCatalogService->getTableMeta(db, table);
EXPECT_TRUE(meta);
unique_ptr<SQueryPlanNode> scan((SQueryPlanNode*)myCalloc(1, sizeof(SQueryPlanNode)));
scan->info.type = scanOp;
scan->numOfCols = meta->schema->tableInfo.numOfColumns;
scan->pSchema = (SSchema*)myCalloc(1, sizeof(SSchema) * scan->numOfCols);
memcpy(scan->pSchema, meta->schema->schema, sizeof(SSchema) * scan->numOfCols);
//todo 'pExpr' 'numOfExpr'
scan->pExtInfo = createScanExtInfo(meta);
pushNode(scan.release());
}
int32_t run() {
SQueryDag* dag = nullptr;
uint64_t requestId = 20;
int32_t code = createDag(logicPlan_.get(), nullptr, &dag, NULL, requestId);
dag_.reset(dag);
return code;
}
int32_t run(const string& db, const string& sql) {
SParseContext cxt;
buildParseContext(db, sql, &cxt);
SQueryNode* query;
int32_t code = qParseQuerySql(&cxt, &query);
if (TSDB_CODE_SUCCESS != code) {
cout << "error no:" << code << ", msg:" << cxt.pMsg << endl;
return code;
}
SQueryDag* dag = nullptr;
uint64_t requestId = 20;
SSchema *schema = NULL;
int32_t numOfOutput = 0;
code = qCreateQueryDag(query, &dag, &schema, &numOfOutput, nullptr, requestId);
dag_.reset(dag);
return code;
}
void explain() {
size_t level = taosArrayGetSize(dag_->pSubplans);
for (size_t i = 0; i < level; ++i) {
std::cout << "level " << i << ":" << std::endl;
const SArray* subplans = (const SArray*)taosArrayGetP(dag_->pSubplans, i);
size_t num = taosArrayGetSize(subplans);
for (size_t j = 0; j < num; ++j) {
std::cout << "no " << j << ":" << std::endl;
int32_t len = 0;
char* str = nullptr;
ASSERT_EQ(TSDB_CODE_SUCCESS, qSubPlanToString((const SSubplan*)taosArrayGetP(subplans, j), &str, &len));
std::cout << "len:" << len << std::endl;
std::cout << str << std::endl;
free(str);
}
}
}
SQueryDag* result() {
return dag_.get();
}
private:
void pushNode(SQueryPlanNode* node) {
if (logicPlan_) {
node->pChildren = taosArrayInit(TARRAY_MIN_SIZE, POINTER_BYTES);
SQueryPlanNode* child = logicPlan_.release();
taosArrayPush(node->pChildren, &child);
}
logicPlan_.reset(node);
}
void copySchemaMeta(STableMeta** dst, const STableMeta* src) {
int32_t size = sizeof(STableMeta) + sizeof(SSchema) * (src->tableInfo.numOfTags + src->tableInfo.numOfColumns);
*dst = (STableMeta*)myCalloc(1, size);
memcpy(*dst, src, size);
}
void copyStorageMeta(SVgroupsInfo** dst, const std::vector<SVgroupInfo>& src) {
*dst = (SVgroupsInfo*)myCalloc(1, sizeof(SVgroupsInfo) + sizeof(SVgroupInfo) * src.size());
(*dst)->numOfVgroups = src.size();
for (int32_t i = 0; i < src.size(); ++i) {
(*dst)->vgroups[i] = src[i];
}
}
SQueryTableInfo* createScanExtInfo(shared_ptr<MockTableMeta>& meta) {
SQueryTableInfo* info = (SQueryTableInfo*)myCalloc(1, sizeof(SQueryTableInfo));
info->pMeta = (STableMetaInfo*)myCalloc(1, sizeof(STableMetaInfo));
copySchemaMeta(&info->pMeta->pTableMeta, meta->schema.get());
copyStorageMeta(&info->pMeta->vgroupList, meta->vgs);
return info;
}
void buildParseContext(const string& db, const string& sql, SParseContext* pCxt) {
static string _db;
static string _sql;
static const int32_t _msgMaxLen = 4096;
static char _msg[_msgMaxLen];
_db = db;
_sql = sql;
memset(_msg, 0, _msgMaxLen);
pCxt->acctId = 1;
pCxt->db = _db.c_str();
pCxt->requestId = 1;
pCxt->pSql = _sql.c_str();
pCxt->sqlLen = _sql.length();
pCxt->pMsg = _msg;
pCxt->msgLen = _msgMaxLen;
}
shared_ptr<MockTableMeta> meta_;
unique_ptr<SQueryPlanNode> logicPlan_;
unique_ptr<SQueryDag> dag_;
};
// select * from table
TEST_F(PhyPlanTest, tableScanTest) {
pushScan("test", "t1", QNODE_TABLESCAN);
ASSERT_EQ(run(), TSDB_CODE_SUCCESS);
explain();
SQueryDag* dag = result();
// todo check
}
TEST_F(PhyPlanTest, serializeTest) {
pushScan("test", "t1", QNODE_TABLESCAN);
ASSERT_EQ(run(), TSDB_CODE_SUCCESS);
SQueryDag* dag = result();
cout << qDagToString(dag) << endl;
}
// select * from supertable
TEST_F(PhyPlanTest, superTableScanTest) {
pushScan("test", "st1", QNODE_TABLESCAN);
ASSERT_EQ(run(), TSDB_CODE_SUCCESS);
explain();
SQueryDag* dag = result();
// todo check
}
// select count(*) from table
TEST_F(PhyPlanTest, simpleAggTest) {
pushScan("test", "t1", QNODE_TABLESCAN);
pushAgg(QNODE_AGGREGATE);
ASSERT_EQ(run(), TSDB_CODE_SUCCESS);
explain();
SQueryDag* dag = result();
// todo check
}
// insert into t values(...)
TEST_F(PhyPlanTest, insertTest) {
ASSERT_EQ(run("test", "insert into t1 values (now, 1, \"beijing\")"), TSDB_CODE_SUCCESS);
explain();
SQueryDag* dag = result();
// todo check
}
#endif
\ No newline at end of file
source/libs/planner/test/
newP
lannerTest.cpp
→
source/libs/planner/test/
p
lannerTest.cpp
浏览文件 @
cd7a0e55
...
@@ -17,8 +17,8 @@
...
@@ -17,8 +17,8 @@
#include <gtest/gtest.h>
#include <gtest/gtest.h>
#include "plannerImpl.h"
#include "parser.h"
#include "parser.h"
#include "plannerInt.h"
using
namespace
std
;
using
namespace
std
;
using
namespace
testing
;
using
namespace
testing
;
...
@@ -56,7 +56,8 @@ protected:
...
@@ -56,7 +56,8 @@ protected:
const
string
syntaxTreeStr
=
toString
(
query_
->
pRoot
,
false
);
const
string
syntaxTreeStr
=
toString
(
query_
->
pRoot
,
false
);
SLogicNode
*
pLogicPlan
=
nullptr
;
SLogicNode
*
pLogicPlan
=
nullptr
;
code
=
createLogicPlan
(
query_
->
pRoot
,
&
pLogicPlan
);
SPlanContext
cxt
=
{
.
queryId
=
1
,
.
pAstRoot
=
query_
->
pRoot
};
code
=
createLogicPlan
(
&
cxt
,
&
pLogicPlan
);
if
(
code
!=
TSDB_CODE_SUCCESS
)
{
if
(
code
!=
TSDB_CODE_SUCCESS
)
{
cout
<<
"sql:["
<<
cxt_
.
pSql
<<
"] logic plan code:"
<<
code
<<
", strerror:"
<<
tstrerror
(
code
)
<<
endl
;
cout
<<
"sql:["
<<
cxt_
.
pSql
<<
"] logic plan code:"
<<
code
<<
", strerror:"
<<
tstrerror
(
code
)
<<
endl
;
return
false
;
return
false
;
...
...
source/libs/p
arser/inc/astCreateContext.h
→
source/libs/p
lanner/test/plannerTestMain.cpp
浏览文件 @
cd7a0e55
...
@@ -13,28 +13,29 @@
...
@@ -13,28 +13,29 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
*/
#ifndef _TD_AST_CREATER_H_
#include <string>
#define _TD_AST_CREATER_H_
#ifdef __cplusplus
#include <gtest/gtest.h>
extern
"C"
{
#endif
#include "nodes.h"
#include "mockCatalog.h"
#include "parser.h"
typedef
struct
SAstCreateContex
t
{
class
PlannerEnv
:
public
testing
::
Environmen
t
{
SParseContext
*
pQueryCxt
;
public:
bool
notSupport
;
virtual
void
SetUp
()
{
bool
valid
;
initMetaDataEnv
()
;
SNode
*
pRootNode
;
generateMetaData
()
;
}
SAstCreateContext
;
}
int32_t
createAstCreateContext
(
SParseContext
*
pQueryCxt
,
SAstCreateContext
*
pCxt
);
virtual
void
TearDown
()
{
int32_t
destroyAstCreateContext
(
SAstCreateContext
*
pCxt
);
destroyMetaDataEnv
();
}
#ifdef __cplusplus
PlannerEnv
()
{}
}
virtual
~
PlannerEnv
()
{
}
#endif
};
#endif
/*_TD_AST_CREATER_H_*/
int
main
(
int
argc
,
char
*
argv
[])
{
testing
::
AddGlobalTestEnvironment
(
new
PlannerEnv
());
testing
::
InitGoogleTest
(
&
argc
,
argv
);
return
RUN_ALL_TESTS
();
}
source/libs/planner/test/plannerTests.cpp
已删除
100644 → 0
浏览文件 @
768e0593
/*
* 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 <gtest/gtest.h>
#include <iostream>
#include "os.h"
#include "taos.h"
#include "parser.h"
#include "mockCatalog.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wwrite-strings"
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wsign-compare"
class
PlannerEnv
:
public
testing
::
Environment
{
public:
virtual
void
SetUp
()
{
initMetaDataEnv
();
generateMetaData
();
}
virtual
void
TearDown
()
{
destroyMetaDataEnv
();
}
PlannerEnv
()
{}
virtual
~
PlannerEnv
()
{}
};
int
main
(
int
argc
,
char
*
argv
[])
{
testing
::
AddGlobalTestEnvironment
(
new
PlannerEnv
());
testing
::
InitGoogleTest
(
&
argc
,
argv
);
return
RUN_ALL_TESTS
();
}
TEST
(
testCase
,
planner_test
)
{
char
msg
[
128
]
=
{
0
};
const
char
*
sql
=
"select top(a*b / 99, 20) from `t.1abc` interval(10s, 1s)"
;
// SQueryStmtInfo* pQueryInfo = nullptr;
// int32_t code = qParseQuerySql(sql, strlen(sql), &pQueryInfo, 0, msg, sizeof(msg));
// ASSERT_EQ(code, 0);
// SSqlNode* pNode = (SSqlNode*)taosArrayGetP(((SArray*)info1.list), 0);
// int32_t code = evaluateSqlNode(pNode, TSDB_TIME_PRECISION_NANO, &buf);
// ASSERT_EQ(code, 0);
//
// SMetaReq req = {0};
// int32_t ret = qParserExtractRequestedMetaInfo(&info1, &req, msg, 128);
// ASSERT_EQ(ret, 0);
// ASSERT_EQ(taosArrayGetSize(req.pTableName), 1);
//
// SQueryStmtInfo* pQueryInfo = createQueryInfo();
// setTableMetaInfo(pQueryInfo, &req);
//
// SSqlNode* pSqlNode = (SSqlNode*)taosArrayGetP(info1.list, 0);
// ret = validateSqlNode(pSqlNode, pQueryInfo, &buf);
// ASSERT_EQ(ret, 0);
//
// SArray* pExprList = pQueryInfo->exprList;
// ASSERT_EQ(taosArrayGetSize(pExprList), 2);
//
// SExprInfo* p1 = (SExprInfo*)taosArrayGetP(pExprList, 1);
// ASSERT_EQ(p1->base.uid, 110);
// ASSERT_EQ(p1->base.numOfParams, 1);
// ASSERT_EQ(p1->base.resSchema.type, TSDB_DATA_TYPE_DOUBLE);
// ASSERT_STRCASEEQ(p1->base.resSchema.name, "top(a*b / 99, 20)");
// ASSERT_EQ(p1->base.colInfo.flag, TSDB_COL_NORMAL);
// ASSERT_STRCASEEQ(p1->base.token, "top(a*b / 99, 20)");
// ASSERT_EQ(p1->base.interBytes, 16);
//
// ASSERT_EQ(p1->pExpr->nodeType, TEXPR_UNARYEXPR_NODE);
// ASSERT_EQ(p1->pExpr->_node.functionId, FUNCTION_TOP);
// ASSERT_TRUE(p1->pExpr->_node.pRight == NULL);
//
// tExprNode* pParam = p1->pExpr->_node.pLeft;
//
// ASSERT_EQ(pParam->nodeType, TEXPR_BINARYEXPR_NODE);
// ASSERT_EQ(pParam->_node.optr, TSDB_BINARY_OP_DIVIDE);
// ASSERT_EQ(pParam->_node.pLeft->nodeType, TEXPR_BINARYEXPR_NODE);
// ASSERT_EQ(pParam->_node.pRight->nodeType, TEXPR_VALUE_NODE);
//
// ASSERT_EQ(taosArrayGetSize(pQueryInfo->colList), 3);
// ASSERT_EQ(pQueryInfo->fieldsInfo.numOfOutput, 2);
//
// destroyQueryInfo(pQueryInfo);
// qParserCleanupMetaRequestInfo(&req);
// destroySqlInfo(&info1);
}
#pragma GCC diagnostic pop
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录