feat: fill physical plan
This commit is contained in:
parent
913354057e
commit
cdfe9929c8
|
@ -28,6 +28,7 @@ typedef int64_t tb_uid_t;
|
||||||
#define TSWINDOW_INITIALIZER ((STimeWindow){INT64_MIN, INT64_MAX})
|
#define TSWINDOW_INITIALIZER ((STimeWindow){INT64_MIN, INT64_MAX})
|
||||||
#define TSWINDOW_DESC_INITIALIZER ((STimeWindow){INT64_MAX, INT64_MIN})
|
#define TSWINDOW_DESC_INITIALIZER ((STimeWindow){INT64_MAX, INT64_MIN})
|
||||||
#define IS_TSWINDOW_SPECIFIED(win) (((win).skey != INT64_MIN) || ((win).ekey != INT64_MAX))
|
#define IS_TSWINDOW_SPECIFIED(win) (((win).skey != INT64_MIN) || ((win).ekey != INT64_MAX))
|
||||||
|
#define TSWINDOW_IS_EQUAL(t1, t2) (((t1).skey == (t2).skey) && ((t1).ekey == (t2).ekey))
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TSDB_SUPER_TABLE = 1, // super table
|
TSDB_SUPER_TABLE = 1, // super table
|
||||||
|
|
|
@ -114,6 +114,7 @@ typedef struct SFillLogicNode {
|
||||||
EFillMode mode;
|
EFillMode mode;
|
||||||
SNode* pWStartTs;
|
SNode* pWStartTs;
|
||||||
SNode* pValues; // SNodeListNode
|
SNode* pValues; // SNodeListNode
|
||||||
|
STimeWindow timeRange;
|
||||||
} SFillLogicNode;
|
} SFillLogicNode;
|
||||||
|
|
||||||
typedef struct SSortLogicNode {
|
typedef struct SSortLogicNode {
|
||||||
|
@ -279,6 +280,7 @@ typedef struct SFillPhysiNode {
|
||||||
SNode* pWStartTs; // SColumnNode
|
SNode* pWStartTs; // SColumnNode
|
||||||
SNode* pValues; // SNodeListNode
|
SNode* pValues; // SNodeListNode
|
||||||
SNodeList* pTargets;
|
SNodeList* pTargets;
|
||||||
|
STimeWindow timeRange;
|
||||||
} SFillPhysiNode;
|
} SFillPhysiNode;
|
||||||
|
|
||||||
typedef struct SMultiTableIntervalPhysiNode {
|
typedef struct SMultiTableIntervalPhysiNode {
|
||||||
|
|
|
@ -213,6 +213,7 @@ typedef struct SFillNode {
|
||||||
EFillMode mode;
|
EFillMode mode;
|
||||||
SNode* pValues; // SNodeListNode
|
SNode* pValues; // SNodeListNode
|
||||||
SNode* pWStartTs; // _wstartts pseudo column
|
SNode* pWStartTs; // _wstartts pseudo column
|
||||||
|
STimeWindow timeRange;
|
||||||
} SFillNode;
|
} SFillNode;
|
||||||
|
|
||||||
typedef struct SSelectStmt {
|
typedef struct SSelectStmt {
|
||||||
|
|
|
@ -619,9 +619,12 @@ int32_t* taosGetErrno();
|
||||||
#define TSDB_CODE_PAR_SLIMIT_LEAK_PARTITION_BY TAOS_DEF_ERROR_CODE(0, 0x2638)
|
#define TSDB_CODE_PAR_SLIMIT_LEAK_PARTITION_BY TAOS_DEF_ERROR_CODE(0, 0x2638)
|
||||||
#define TSDB_CODE_PAR_INVALID_TOPIC_QUERY TAOS_DEF_ERROR_CODE(0, 0x2639)
|
#define TSDB_CODE_PAR_INVALID_TOPIC_QUERY TAOS_DEF_ERROR_CODE(0, 0x2639)
|
||||||
#define TSDB_CODE_PAR_INVALID_DROP_STABLE TAOS_DEF_ERROR_CODE(0, 0x263A)
|
#define TSDB_CODE_PAR_INVALID_DROP_STABLE TAOS_DEF_ERROR_CODE(0, 0x263A)
|
||||||
|
#define TSDB_CODE_PAR_INVALID_FILL_TIME_RANGE TAOS_DEF_ERROR_CODE(0, 0x263B)
|
||||||
|
|
||||||
//planner
|
//planner
|
||||||
#define TSDB_CODE_PLAN_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x2700)
|
#define TSDB_CODE_PLAN_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x2700)
|
||||||
|
#define TSDB_CODE_PLAN_EXPECTED_TS_EQUAL TAOS_DEF_ERROR_CODE(0, 0x2701)
|
||||||
|
#define TSDB_CODE_PLAN_NOT_SUPPORT_CROSS_JOIN TAOS_DEF_ERROR_CODE(0, 0x2702)
|
||||||
|
|
||||||
//function
|
//function
|
||||||
#define TSDB_CODE_FUNC_FUNTION_ERROR TAOS_DEF_ERROR_CODE(0, 0x2800)
|
#define TSDB_CODE_FUNC_FUNTION_ERROR TAOS_DEF_ERROR_CODE(0, 0x2800)
|
||||||
|
|
|
@ -41,8 +41,6 @@
|
||||||
#define SET_MAIN_SCAN_FLAG(runtime) ((runtime)->scanFlag = MAIN_SCAN)
|
#define SET_MAIN_SCAN_FLAG(runtime) ((runtime)->scanFlag = MAIN_SCAN)
|
||||||
#define SET_REVERSE_SCAN_FLAG(runtime) ((runtime)->scanFlag = REVERSE_SCAN)
|
#define SET_REVERSE_SCAN_FLAG(runtime) ((runtime)->scanFlag = REVERSE_SCAN)
|
||||||
|
|
||||||
#define TSWINDOW_IS_EQUAL(t1, t2) (((t1).skey == (t2).skey) && ((t1).ekey == (t2).ekey))
|
|
||||||
|
|
||||||
#define SDATA_BLOCK_INITIALIZER \
|
#define SDATA_BLOCK_INITIALIZER \
|
||||||
(SDataBlockInfo) { {0}, 0 }
|
(SDataBlockInfo) { {0}, 0 }
|
||||||
|
|
||||||
|
|
|
@ -571,6 +571,8 @@ static int32_t jsonToLogicProjectNode(const SJson* pJson, void* pObj) {
|
||||||
static const char* jkFillLogicPlanMode = "Mode";
|
static const char* jkFillLogicPlanMode = "Mode";
|
||||||
static const char* jkFillLogicPlanWStartTs = "WStartTs";
|
static const char* jkFillLogicPlanWStartTs = "WStartTs";
|
||||||
static const char* jkFillLogicPlanValues = "Values";
|
static const char* jkFillLogicPlanValues = "Values";
|
||||||
|
static const char* jkFillLogicPlanStartTime = "StartTime";
|
||||||
|
static const char* jkFillLogicPlanEndTime = "EndTime";
|
||||||
|
|
||||||
static int32_t logicFillNodeToJson(const void* pObj, SJson* pJson) {
|
static int32_t logicFillNodeToJson(const void* pObj, SJson* pJson) {
|
||||||
const SFillLogicNode* pNode = (const SFillLogicNode*)pObj;
|
const SFillLogicNode* pNode = (const SFillLogicNode*)pObj;
|
||||||
|
@ -585,6 +587,12 @@ static int32_t logicFillNodeToJson(const void* pObj, SJson* pJson) {
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = tjsonAddObject(pJson, jkFillLogicPlanValues, nodeToJson, pNode->pValues);
|
code = tjsonAddObject(pJson, jkFillLogicPlanValues, nodeToJson, pNode->pValues);
|
||||||
}
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = tjsonAddIntegerToObject(pJson, jkFillLogicPlanStartTime, pNode->timeRange.skey);
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = tjsonAddIntegerToObject(pJson, jkFillLogicPlanEndTime, pNode->timeRange.ekey);
|
||||||
|
}
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -602,6 +610,12 @@ static int32_t jsonToLogicFillNode(const SJson* pJson, void* pObj) {
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = jsonToNodeObject(pJson, jkFillLogicPlanValues, &pNode->pValues);
|
code = jsonToNodeObject(pJson, jkFillLogicPlanValues, &pNode->pValues);
|
||||||
}
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = tjsonGetBigIntValue(pJson, jkFillLogicPlanStartTime, &pNode->timeRange.skey);
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = tjsonGetBigIntValue(pJson, jkFillLogicPlanEndTime, &pNode->timeRange.ekey);
|
||||||
|
}
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -1475,6 +1489,8 @@ static const char* jkFillPhysiPlanMode = "Mode";
|
||||||
static const char* jkFillPhysiPlanWStartTs = "WStartTs";
|
static const char* jkFillPhysiPlanWStartTs = "WStartTs";
|
||||||
static const char* jkFillPhysiPlanValues = "Values";
|
static const char* jkFillPhysiPlanValues = "Values";
|
||||||
static const char* jkFillPhysiPlanTargets = "Targets";
|
static const char* jkFillPhysiPlanTargets = "Targets";
|
||||||
|
static const char* jkFillPhysiPlanStartTime = "StartTime";
|
||||||
|
static const char* jkFillPhysiPlanEndTime = "EndTime";
|
||||||
|
|
||||||
static int32_t physiFillNodeToJson(const void* pObj, SJson* pJson) {
|
static int32_t physiFillNodeToJson(const void* pObj, SJson* pJson) {
|
||||||
const SFillPhysiNode* pNode = (const SFillPhysiNode*)pObj;
|
const SFillPhysiNode* pNode = (const SFillPhysiNode*)pObj;
|
||||||
|
@ -1492,6 +1508,12 @@ static int32_t physiFillNodeToJson(const void* pObj, SJson* pJson) {
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = nodeListToJson(pJson, jkFillPhysiPlanTargets, pNode->pTargets);
|
code = nodeListToJson(pJson, jkFillPhysiPlanTargets, pNode->pTargets);
|
||||||
}
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = tjsonAddIntegerToObject(pJson, jkFillPhysiPlanStartTime, pNode->timeRange.skey);
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = tjsonAddIntegerToObject(pJson, jkFillPhysiPlanEndTime, pNode->timeRange.ekey);
|
||||||
|
}
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -1512,6 +1534,12 @@ static int32_t jsonToPhysiFillNode(const SJson* pJson, void* pObj) {
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = jsonToNodeList(pJson, jkFillPhysiPlanTargets, &pNode->pTargets);
|
code = jsonToNodeList(pJson, jkFillPhysiPlanTargets, &pNode->pTargets);
|
||||||
}
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = tjsonGetBigIntValue(pJson, jkFillPhysiPlanStartTime, &pNode->timeRange.skey);
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = tjsonGetBigIntValue(pJson, jkFillPhysiPlanEndTime, &pNode->timeRange.ekey);
|
||||||
|
}
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -2409,6 +2437,8 @@ static int32_t jsonToNodeListNode(const SJson* pJson, void* pObj) {
|
||||||
static const char* jkFillMode = "Mode";
|
static const char* jkFillMode = "Mode";
|
||||||
static const char* jkFillValues = "Values";
|
static const char* jkFillValues = "Values";
|
||||||
static const char* jkFillWStartTs = "WStartTs";
|
static const char* jkFillWStartTs = "WStartTs";
|
||||||
|
static const char* jkFillStartTime = "StartTime";
|
||||||
|
static const char* jkFillEndTime = "EndTime";
|
||||||
|
|
||||||
static int32_t fillNodeToJson(const void* pObj, SJson* pJson) {
|
static int32_t fillNodeToJson(const void* pObj, SJson* pJson) {
|
||||||
const SFillNode* pNode = (const SFillNode*)pObj;
|
const SFillNode* pNode = (const SFillNode*)pObj;
|
||||||
|
@ -2420,6 +2450,12 @@ static int32_t fillNodeToJson(const void* pObj, SJson* pJson) {
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = tjsonAddObject(pJson, jkFillWStartTs, nodeToJson, pNode->pWStartTs);
|
code = tjsonAddObject(pJson, jkFillWStartTs, nodeToJson, pNode->pWStartTs);
|
||||||
}
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = tjsonAddIntegerToObject(pJson, jkFillStartTime, pNode->timeRange.skey);
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = tjsonAddIntegerToObject(pJson, jkFillEndTime, pNode->timeRange.ekey);
|
||||||
|
}
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -2434,6 +2470,12 @@ static int32_t jsonToFillNode(const SJson* pJson, void* pObj) {
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = jsonToNodeObject(pJson, jkFillWStartTs, &pNode->pWStartTs);
|
code = jsonToNodeObject(pJson, jkFillWStartTs, &pNode->pWStartTs);
|
||||||
}
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = tjsonGetBigIntValue(pJson, jkFillStartTime, &pNode->timeRange.skey);
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = tjsonGetBigIntValue(pJson, jkFillEndTime, &pNode->timeRange.ekey);
|
||||||
|
}
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "catalog.h"
|
#include "catalog.h"
|
||||||
#include "cmdnodes.h"
|
#include "cmdnodes.h"
|
||||||
|
#include "filter.h"
|
||||||
#include "functionMgt.h"
|
#include "functionMgt.h"
|
||||||
#include "parUtil.h"
|
#include "parUtil.h"
|
||||||
#include "scalar.h"
|
#include "scalar.h"
|
||||||
|
@ -1244,6 +1245,113 @@ static int32_t translateGroupBy(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static EDealRes isPrimaryKeyCondImpl(SNode* pNode, void* pContext) {
|
||||||
|
if (QUERY_NODE_COLUMN == nodeType(pNode)) {
|
||||||
|
*((bool*)pContext) = ((PRIMARYKEY_TIMESTAMP_COL_ID == ((SColumnNode*)pNode)->colId) ? true : false);
|
||||||
|
return *((bool*)pContext) ? DEAL_RES_CONTINUE : DEAL_RES_END;
|
||||||
|
}
|
||||||
|
return DEAL_RES_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isPrimaryKeyCond(SNode* pNode) {
|
||||||
|
bool isPrimaryKeyCond = false;
|
||||||
|
nodesWalkExpr(pNode, isPrimaryKeyCondImpl, &isPrimaryKeyCond);
|
||||||
|
return isPrimaryKeyCond;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t getTimeRangeFromLogicCond(STranslateContext* pCxt, SLogicConditionNode* pLogicCond,
|
||||||
|
STimeWindow* pTimeRange) {
|
||||||
|
SNodeList* pPrimaryKeyConds = NULL;
|
||||||
|
SNode* pCond = NULL;
|
||||||
|
FOREACH(pCond, pLogicCond->pParameterList) {
|
||||||
|
if (isPrimaryKeyCond(pCond)) {
|
||||||
|
if (TSDB_CODE_SUCCESS != nodesListMakeAppend(&pPrimaryKeyConds, pCond)) {
|
||||||
|
nodesClearList(pPrimaryKeyConds);
|
||||||
|
return TSDB_CODE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL == pPrimaryKeyConds) {
|
||||||
|
*pTimeRange = TSWINDOW_INITIALIZER;
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SLogicConditionNode* pPrimaryKeyLogicCond = nodesMakeNode(QUERY_NODE_LOGIC_CONDITION);
|
||||||
|
if (NULL == pPrimaryKeyLogicCond) {
|
||||||
|
nodesClearList(pPrimaryKeyConds);
|
||||||
|
return TSDB_CODE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
pPrimaryKeyLogicCond->condType = LOGIC_COND_TYPE_AND;
|
||||||
|
pPrimaryKeyLogicCond->pParameterList = pPrimaryKeyConds;
|
||||||
|
bool isStrict = false;
|
||||||
|
int32_t code = filterGetTimeRange((SNode*)pPrimaryKeyLogicCond, pTimeRange, &isStrict);
|
||||||
|
nodesClearList(pPrimaryKeyConds);
|
||||||
|
pPrimaryKeyLogicCond->pParameterList = NULL;
|
||||||
|
nodesDestroyNode(pPrimaryKeyLogicCond);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t getTimeRange(STranslateContext* pCxt, SNode* pWhere, STimeWindow* pTimeRange) {
|
||||||
|
if (NULL == pWhere) {
|
||||||
|
*pTimeRange = TSWINDOW_INITIALIZER;
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QUERY_NODE_LOGIC_CONDITION == nodeType(pWhere) &&
|
||||||
|
LOGIC_COND_TYPE_AND == ((SLogicConditionNode*)pWhere)->condType) {
|
||||||
|
return getTimeRangeFromLogicCond(pCxt, (SLogicConditionNode*)pWhere, pTimeRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPrimaryKeyCond(pWhere)) {
|
||||||
|
bool isStrict = false;
|
||||||
|
return filterGetTimeRange(pWhere, pTimeRange, &isStrict);
|
||||||
|
} else {
|
||||||
|
*pTimeRange = TSWINDOW_INITIALIZER;
|
||||||
|
}
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t checkFill(STranslateContext* pCxt, SIntervalWindowNode* pInterval) {
|
||||||
|
SFillNode* pFill = (SFillNode*)pInterval->pFill;
|
||||||
|
if (TSWINDOW_IS_EQUAL(pFill->timeRange, TSWINDOW_INITIALIZER) ||
|
||||||
|
TSWINDOW_IS_EQUAL(pFill->timeRange, TSWINDOW_DESC_INITIALIZER)) {
|
||||||
|
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_FILL_TIME_RANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t timeRange = TABS(pFill->timeRange.skey - pFill->timeRange.ekey);
|
||||||
|
int64_t intervalRange = 0;
|
||||||
|
SValueNode* pInter = (SValueNode*)pInterval->pInterval;
|
||||||
|
if (TIME_IS_VAR_DURATION(pInter->unit)) {
|
||||||
|
int64_t f = 1;
|
||||||
|
if (pInter->unit == 'n') {
|
||||||
|
f = 30L * MILLISECOND_PER_DAY;
|
||||||
|
} else if (pInter->unit == 'y') {
|
||||||
|
f = 365L * MILLISECOND_PER_DAY;
|
||||||
|
}
|
||||||
|
intervalRange = pInter->datum.i * f;
|
||||||
|
} else {
|
||||||
|
intervalRange = pInter->datum.i;
|
||||||
|
}
|
||||||
|
if ((timeRange == 0) || (timeRange / intervalRange) >= MAX_INTERVAL_TIME_WINDOW) {
|
||||||
|
return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_FILL_TIME_RANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t translateFill(STranslateContext* pCxt, SNode* pWhere, SIntervalWindowNode* pInterval) {
|
||||||
|
if (NULL == pInterval->pFill) {
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t code = getTimeRange(pCxt, pWhere, &(((SFillNode*)pInterval->pFill)->timeRange));
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = checkFill(pCxt, pInterval);
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
static int64_t getMonthsFromTimeVal(int64_t val, int32_t fromPrecision, char unit) {
|
static int64_t getMonthsFromTimeVal(int64_t val, int32_t fromPrecision, char unit) {
|
||||||
int64_t days = convertTimeFromPrecisionToUnit(val, fromPrecision, 'd');
|
int64_t days = convertTimeFromPrecisionToUnit(val, fromPrecision, 'd');
|
||||||
switch (unit) {
|
switch (unit) {
|
||||||
|
@ -1266,7 +1374,7 @@ static int64_t getMonthsFromTimeVal(int64_t val, int32_t fromPrecision, char uni
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t checkIntervalWindow(STranslateContext* pCxt, SIntervalWindowNode* pInterval) {
|
static int32_t checkIntervalWindow(STranslateContext* pCxt, SNode* pWhere, SIntervalWindowNode* pInterval) {
|
||||||
uint8_t precision = ((SColumnNode*)pInterval->pCol)->node.resType.precision;
|
uint8_t precision = ((SColumnNode*)pInterval->pCol)->node.resType.precision;
|
||||||
|
|
||||||
SValueNode* pInter = (SValueNode*)pInterval->pInterval;
|
SValueNode* pInter = (SValueNode*)pInterval->pInterval;
|
||||||
|
@ -1308,7 +1416,7 @@ static int32_t checkIntervalWindow(STranslateContext* pCxt, SIntervalWindowNode*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TSDB_CODE_SUCCESS;
|
return translateFill(pCxt, pWhere, pInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
static EDealRes checkStateExpr(SNode* pNode, void* pContext) {
|
static EDealRes checkStateExpr(SNode* pNode, void* pContext) {
|
||||||
|
@ -1345,28 +1453,28 @@ static int32_t checkSessionWindow(STranslateContext* pCxt, SSessionWindowNode* p
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t checkWindow(STranslateContext* pCxt, SNode* pWindow) {
|
static int32_t checkWindow(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
switch (nodeType(pWindow)) {
|
switch (nodeType(pSelect->pWindow)) {
|
||||||
case QUERY_NODE_STATE_WINDOW:
|
case QUERY_NODE_STATE_WINDOW:
|
||||||
return checkStateWindow(pCxt, (SStateWindowNode*)pWindow);
|
return checkStateWindow(pCxt, (SStateWindowNode*)pSelect->pWindow);
|
||||||
case QUERY_NODE_SESSION_WINDOW:
|
case QUERY_NODE_SESSION_WINDOW:
|
||||||
return checkSessionWindow(pCxt, (SSessionWindowNode*)pWindow);
|
return checkSessionWindow(pCxt, (SSessionWindowNode*)pSelect->pWindow);
|
||||||
case QUERY_NODE_INTERVAL_WINDOW:
|
case QUERY_NODE_INTERVAL_WINDOW:
|
||||||
return checkIntervalWindow(pCxt, (SIntervalWindowNode*)pWindow);
|
return checkIntervalWindow(pCxt, pSelect->pWhere, (SIntervalWindowNode*)pSelect->pWindow);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t translateWindow(STranslateContext* pCxt, SNode* pWindow) {
|
static int32_t translateWindow(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
if (NULL == pWindow) {
|
if (NULL == pSelect->pWindow) {
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
pCxt->currClause = SQL_CLAUSE_WINDOW;
|
pCxt->currClause = SQL_CLAUSE_WINDOW;
|
||||||
int32_t code = translateExpr(pCxt, pWindow);
|
int32_t code = translateExpr(pCxt, pSelect->pWindow);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = checkWindow(pCxt, pWindow);
|
code = checkWindow(pCxt, pSelect);
|
||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -1485,7 +1593,7 @@ static int32_t translateSelect(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
code = translatePartitionBy(pCxt, pSelect->pPartitionByList);
|
code = translatePartitionBy(pCxt, pSelect->pPartitionByList);
|
||||||
}
|
}
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = translateWindow(pCxt, pSelect->pWindow);
|
code = translateWindow(pCxt, pSelect);
|
||||||
}
|
}
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = translateGroupBy(pCxt, pSelect);
|
code = translateGroupBy(pCxt, pSelect);
|
||||||
|
|
|
@ -128,6 +128,8 @@ static char* getSyntaxErrFormat(int32_t errCode) {
|
||||||
return "Invalid topic query";
|
return "Invalid topic query";
|
||||||
case TSDB_CODE_PAR_INVALID_DROP_STABLE:
|
case TSDB_CODE_PAR_INVALID_DROP_STABLE:
|
||||||
return "Cannot drop super table in batch";
|
return "Cannot drop super table in batch";
|
||||||
|
case TSDB_CODE_PAR_INVALID_FILL_TIME_RANGE:
|
||||||
|
return "start(end) time of query range required or time range too large";
|
||||||
case TSDB_CODE_OUT_OF_MEMORY:
|
case TSDB_CODE_OUT_OF_MEMORY:
|
||||||
return "Out of memory";
|
return "Out of memory";
|
||||||
default:
|
default:
|
||||||
|
@ -140,7 +142,6 @@ int32_t generateSyntaxErrMsg(SMsgBuf* pBuf, int32_t errCode, ...) {
|
||||||
va_start(vArgList, errCode);
|
va_start(vArgList, errCode);
|
||||||
vsnprintf(pBuf->buf, pBuf->len, getSyntaxErrFormat(errCode), vArgList);
|
vsnprintf(pBuf->buf, pBuf->len, getSyntaxErrFormat(errCode), vArgList);
|
||||||
va_end(vArgList);
|
va_end(vArgList);
|
||||||
terrno = errCode;
|
|
||||||
return errCode;
|
return errCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ TEST_F(ParserSelectTest, basic) {
|
||||||
|
|
||||||
run("SELECT ts, t.c1 FROM (SELECT * FROM t1) t");
|
run("SELECT ts, t.c1 FROM (SELECT * FROM t1) t");
|
||||||
|
|
||||||
run("SELECT * FROM t1 tt1, t1 tt2 where tt1.c1 = tt2.c1");
|
run("SELECT * FROM t1 tt1, t1 tt2 WHERE tt1.c1 = tt2.c1");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserSelectTest, constant) {
|
TEST_F(ParserSelectTest, constant) {
|
||||||
|
@ -43,7 +43,7 @@ TEST_F(ParserSelectTest, constant) {
|
||||||
run("SELECT 1234567890123456789012345678901234567890, 20.1234567890123456789012345678901234567890, 'abc', \"wxy\", "
|
run("SELECT 1234567890123456789012345678901234567890, 20.1234567890123456789012345678901234567890, 'abc', \"wxy\", "
|
||||||
"timestamp '2022-02-09 17:30:20', true, false, 15s FROM t1");
|
"timestamp '2022-02-09 17:30:20', true, false, 15s FROM t1");
|
||||||
|
|
||||||
run("SELECT 123 + 45 FROM t1 where 2 - 1");
|
run("SELECT 123 + 45 FROM t1 WHERE 2 - 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserSelectTest, expression) {
|
TEST_F(ParserSelectTest, expression) {
|
||||||
|
@ -59,9 +59,9 @@ TEST_F(ParserSelectTest, expression) {
|
||||||
TEST_F(ParserSelectTest, condition) {
|
TEST_F(ParserSelectTest, condition) {
|
||||||
useDb("root", "test");
|
useDb("root", "test");
|
||||||
|
|
||||||
run("SELECT c1 FROM t1 where ts in (true, false)");
|
run("SELECT c1 FROM t1 WHERE ts in (true, false)");
|
||||||
|
|
||||||
run("SELECT * FROM t1 where c1 > 10 and c1 is not null");
|
run("SELECT * FROM t1 WHERE c1 > 10 and c1 is not null");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserSelectTest, pseudoColumn) {
|
TEST_F(ParserSelectTest, pseudoColumn) {
|
||||||
|
@ -77,7 +77,7 @@ TEST_F(ParserSelectTest, multiResFunc) {
|
||||||
|
|
||||||
run("SELECT last(c1, c2), first(t1.*), last_row(c3) FROM t1");
|
run("SELECT last(c1, c2), first(t1.*), last_row(c3) FROM t1");
|
||||||
|
|
||||||
run("SELECT last(t2.*), first(t1.c1, t2.*), last_row(t1.*, t2.*) FROM st1s1 t1, st1s2 t2 where t1.ts = t2.ts");
|
run("SELECT last(t2.*), first(t1.c1, t2.*), last_row(t1.*, t2.*) FROM st1s1 t1, st1s2 t2 WHERE t1.ts = t2.ts");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserSelectTest, timelineFunc) {
|
TEST_F(ParserSelectTest, timelineFunc) {
|
||||||
|
@ -96,29 +96,29 @@ TEST_F(ParserSelectTest, clause) {
|
||||||
useDb("root", "test");
|
useDb("root", "test");
|
||||||
|
|
||||||
// group by clause
|
// group by clause
|
||||||
run("SELECT COUNT(*) cnt FROM t1 where c1 > 0");
|
run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0");
|
||||||
|
|
||||||
run("SELECT COUNT(*), c2 cnt FROM t1 where c1 > 0 group by c2");
|
run("SELECT COUNT(*), c2 cnt FROM t1 WHERE c1 > 0 group by c2");
|
||||||
|
|
||||||
run("SELECT COUNT(*) cnt FROM t1 where c1 > 0 group by c2 having COUNT(c1) > 10");
|
run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0 group by c2 having COUNT(c1) > 10");
|
||||||
|
|
||||||
run("SELECT COUNT(*), c1, c2 + 10, c1 + c2 cnt FROM t1 where c1 > 0 group by c2, c1");
|
run("SELECT COUNT(*), c1, c2 + 10, c1 + c2 cnt FROM t1 WHERE c1 > 0 group by c2, c1");
|
||||||
|
|
||||||
run("SELECT COUNT(*), c1 + 10, c2 cnt FROM t1 where c1 > 0 group by c1 + 10, c2");
|
run("SELECT COUNT(*), c1 + 10, c2 cnt FROM t1 WHERE c1 > 0 group by c1 + 10, c2");
|
||||||
|
|
||||||
// order by clause
|
// order by clause
|
||||||
run("SELECT COUNT(*) cnt FROM t1 where c1 > 0 group by c2 order by cnt");
|
run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0 group by c2 order by cnt");
|
||||||
|
|
||||||
run("SELECT COUNT(*) cnt FROM t1 where c1 > 0 group by c2 order by 1");
|
run("SELECT COUNT(*) cnt FROM t1 WHERE c1 > 0 group by c2 order by 1");
|
||||||
|
|
||||||
// distinct clause
|
// distinct clause
|
||||||
// run("SELECT distinct c1, c2 FROM t1 where c1 > 0 order by c1");
|
// run("SELECT distinct c1, c2 FROM t1 WHERE c1 > 0 order by c1");
|
||||||
|
|
||||||
// run("SELECT distinct c1 + 10, c2 FROM t1 where c1 > 0 order by c1 + 10, c2");
|
// run("SELECT distinct c1 + 10, c2 FROM t1 WHERE c1 > 0 order by c1 + 10, c2");
|
||||||
|
|
||||||
// run("SELECT distinct c1 + 10 cc1, c2 cc2 FROM t1 where c1 > 0 order by cc1, c2");
|
// run("SELECT distinct c1 + 10 cc1, c2 cc2 FROM t1 WHERE c1 > 0 order by cc1, c2");
|
||||||
|
|
||||||
// run("SELECT distinct COUNT(c2) FROM t1 where c1 > 0 group by c1 order by COUNT(c2)");
|
// run("SELECT distinct COUNT(c2) FROM t1 WHERE c1 > 0 group by c1 order by COUNT(c2)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// INTERVAL(interval_val [, interval_offset]) [SLIDING (sliding_val)] [FILL(fill_mod_and_val)]
|
// INTERVAL(interval_val [, interval_offset]) [SLIDING (sliding_val)] [FILL(fill_mod_and_val)]
|
||||||
|
@ -133,7 +133,8 @@ TEST_F(ParserSelectTest, interval) {
|
||||||
// INTERVAL(interval_val, interval_offset) SLIDING (sliding_val)
|
// INTERVAL(interval_val, interval_offset) SLIDING (sliding_val)
|
||||||
run("SELECT COUNT(*) FROM t1 INTERVAL(10s, 5s) SLIDING(7s)");
|
run("SELECT COUNT(*) FROM t1 INTERVAL(10s, 5s) SLIDING(7s)");
|
||||||
// INTERVAL(interval_val) FILL(NONE)
|
// INTERVAL(interval_val) FILL(NONE)
|
||||||
run("SELECT COUNT(*) FROM t1 INTERVAL(10s) FILL(NONE)");
|
run("SELECT COUNT(*) FROM t1 WHERE ts > TIMESTAMP '2022-04-01 00:00:00' and ts < TIMESTAMP '2022-04-30 23:59:59' "
|
||||||
|
"INTERVAL(10s) FILL(NONE)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserSelectTest, semanticError) {
|
TEST_F(ParserSelectTest, semanticError) {
|
||||||
|
@ -152,7 +153,7 @@ TEST_F(ParserSelectTest, semanticError) {
|
||||||
run("SELECT t2.c1 FROM t1", TSDB_CODE_PAR_TABLE_NOT_EXIST, PARSER_STAGE_TRANSLATE);
|
run("SELECT t2.c1 FROM t1", TSDB_CODE_PAR_TABLE_NOT_EXIST, PARSER_STAGE_TRANSLATE);
|
||||||
|
|
||||||
// TSDB_CODE_PAR_AMBIGUOUS_COLUMN
|
// TSDB_CODE_PAR_AMBIGUOUS_COLUMN
|
||||||
run("SELECT c2 FROM t1 tt1, t1 tt2 where tt1.c1 = tt2.c1", TSDB_CODE_PAR_AMBIGUOUS_COLUMN, PARSER_STAGE_TRANSLATE);
|
run("SELECT c2 FROM t1 tt1, t1 tt2 WHERE tt1.c1 = tt2.c1", TSDB_CODE_PAR_AMBIGUOUS_COLUMN, PARSER_STAGE_TRANSLATE);
|
||||||
|
|
||||||
// TSDB_CODE_PAR_WRONG_VALUE_TYPE
|
// TSDB_CODE_PAR_WRONG_VALUE_TYPE
|
||||||
run("SELECT timestamp '2010' FROM t1", TSDB_CODE_PAR_WRONG_VALUE_TYPE, PARSER_STAGE_TRANSLATE);
|
run("SELECT timestamp '2010' FROM t1", TSDB_CODE_PAR_WRONG_VALUE_TYPE, PARSER_STAGE_TRANSLATE);
|
||||||
|
@ -161,7 +162,7 @@ TEST_F(ParserSelectTest, semanticError) {
|
||||||
run("SELECT c2 FROM t1 tt1 join t1 tt2 on COUNT(*) > 0", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION,
|
run("SELECT c2 FROM t1 tt1 join t1 tt2 on COUNT(*) > 0", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION,
|
||||||
PARSER_STAGE_TRANSLATE);
|
PARSER_STAGE_TRANSLATE);
|
||||||
|
|
||||||
run("SELECT c2 FROM t1 where COUNT(*) > 0", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION, PARSER_STAGE_TRANSLATE);
|
run("SELECT c2 FROM t1 WHERE COUNT(*) > 0", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION, PARSER_STAGE_TRANSLATE);
|
||||||
|
|
||||||
run("SELECT c2 FROM t1 group by COUNT(*)", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION, PARSER_STAGE_TRANSLATE);
|
run("SELECT c2 FROM t1 group by COUNT(*)", TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION, PARSER_STAGE_TRANSLATE);
|
||||||
|
|
||||||
|
@ -190,13 +191,13 @@ TEST_F(ParserSelectTest, semanticError) {
|
||||||
run("SELECT c1 FROM t1 order by COUNT(*)", TSDB_CODE_PAR_NOT_SINGLE_GROUP, PARSER_STAGE_TRANSLATE);
|
run("SELECT c1 FROM t1 order by COUNT(*)", TSDB_CODE_PAR_NOT_SINGLE_GROUP, PARSER_STAGE_TRANSLATE);
|
||||||
|
|
||||||
// TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION
|
// TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION
|
||||||
run("SELECT distinct c1, c2 FROM t1 where c1 > 0 order by ts", TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION,
|
run("SELECT distinct c1, c2 FROM t1 WHERE c1 > 0 order by ts", TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION,
|
||||||
PARSER_STAGE_TRANSLATE);
|
PARSER_STAGE_TRANSLATE);
|
||||||
|
|
||||||
run("SELECT distinct c1 FROM t1 where c1 > 0 order by COUNT(c2)", TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION,
|
run("SELECT distinct c1 FROM t1 WHERE c1 > 0 order by COUNT(c2)", TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION,
|
||||||
PARSER_STAGE_TRANSLATE);
|
PARSER_STAGE_TRANSLATE);
|
||||||
|
|
||||||
run("SELECT distinct c2 FROM t1 where c1 > 0 order by COUNT(c2)", TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION,
|
run("SELECT distinct c2 FROM t1 WHERE c1 > 0 order by COUNT(c2)", TSDB_CODE_PAR_NOT_SELECTED_EXPRESSION,
|
||||||
PARSER_STAGE_TRANSLATE);
|
PARSER_STAGE_TRANSLATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "planner.h"
|
#include "planner.h"
|
||||||
|
#include "taoserror.h"
|
||||||
|
|
||||||
#define QUERY_POLICY_VNODE 1
|
#define QUERY_POLICY_VNODE 1
|
||||||
#define QUERY_POLICY_HYBRID 2
|
#define QUERY_POLICY_HYBRID 2
|
||||||
|
@ -33,6 +34,8 @@ extern "C" {
|
||||||
#define planDebug(param, ...) qDebug("PLAN: " param, __VA_ARGS__)
|
#define planDebug(param, ...) qDebug("PLAN: " param, __VA_ARGS__)
|
||||||
#define planTrace(param, ...) qTrace("PLAN: " param, __VA_ARGS__)
|
#define planTrace(param, ...) qTrace("PLAN: " param, __VA_ARGS__)
|
||||||
|
|
||||||
|
int32_t generateUsageErrMsg(char* pBuf, int32_t len, int32_t errCode, ...);
|
||||||
|
|
||||||
int32_t createLogicPlan(SPlanContext* pCxt, SLogicNode** pLogicNode);
|
int32_t createLogicPlan(SPlanContext* pCxt, SLogicNode** pLogicNode);
|
||||||
int32_t optimizeLogicPlan(SPlanContext* pCxt, SLogicNode* pLogicNode);
|
int32_t optimizeLogicPlan(SPlanContext* pCxt, SLogicNode* pLogicNode);
|
||||||
int32_t splitLogicPlan(SPlanContext* pCxt, SLogicNode* pLogicNode, SLogicSubplan** pLogicSubplan);
|
int32_t splitLogicPlan(SPlanContext* pCxt, SLogicNode* pLogicNode, SLogicSubplan** pLogicSubplan);
|
||||||
|
|
|
@ -597,6 +597,7 @@ static int32_t createFillLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect
|
||||||
int32_t code = nodesCollectColumns(pSelect, SQL_CLAUSE_WINDOW, NULL, COLLECT_COL_TYPE_ALL, &pFill->node.pTargets);
|
int32_t code = nodesCollectColumns(pSelect, SQL_CLAUSE_WINDOW, NULL, COLLECT_COL_TYPE_ALL, &pFill->node.pTargets);
|
||||||
|
|
||||||
pFill->mode = pFillNode->mode;
|
pFill->mode = pFillNode->mode;
|
||||||
|
pFill->timeRange = pFillNode->timeRange;
|
||||||
pFill->pValues = nodesCloneNode(pFillNode->pValues);
|
pFill->pValues = nodesCloneNode(pFillNode->pValues);
|
||||||
pFill->pWStartTs = nodesCloneNode(pFillNode->pWStartTs);
|
pFill->pWStartTs = nodesCloneNode(pFillNode->pWStartTs);
|
||||||
if ((NULL != pFillNode->pValues && NULL == pFill->pValues) || NULL == pFill->pWStartTs) {
|
if ((NULL != pFillNode->pValues && NULL == pFill->pValues) || NULL == pFill->pWStartTs) {
|
||||||
|
|
|
@ -554,22 +554,19 @@ static bool cpdIsPrimaryKeyEqualCond(SJoinLogicNode* pJoin, SNode* pCond) {
|
||||||
|
|
||||||
static int32_t cpdCheckOpCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin, SNode* pOnCond) {
|
static int32_t cpdCheckOpCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin, SNode* pOnCond) {
|
||||||
if (!cpdIsPrimaryKeyEqualCond(pJoin, pOnCond)) {
|
if (!cpdIsPrimaryKeyEqualCond(pJoin, pOnCond)) {
|
||||||
snprintf(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, "l.ts = r.ts is expected in join expression");
|
return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_EXPECTED_TS_EQUAL);
|
||||||
return TSDB_CODE_FAILED;
|
|
||||||
}
|
}
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t cpdCheckLogicCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin, SLogicConditionNode* pOnCond) {
|
static int32_t cpdCheckLogicCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin, SLogicConditionNode* pOnCond) {
|
||||||
if (LOGIC_COND_TYPE_AND != pOnCond->condType) {
|
if (LOGIC_COND_TYPE_AND != pOnCond->condType) {
|
||||||
snprintf(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, "l.ts = r.ts is expected in join expression");
|
return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_EXPECTED_TS_EQUAL);
|
||||||
return TSDB_CODE_FAILED;
|
|
||||||
}
|
}
|
||||||
SNode* pCond = NULL;
|
SNode* pCond = NULL;
|
||||||
FOREACH(pCond, pOnCond->pParameterList) {
|
FOREACH(pCond, pOnCond->pParameterList) {
|
||||||
if (!cpdIsPrimaryKeyEqualCond(pJoin, pCond)) {
|
if (!cpdIsPrimaryKeyEqualCond(pJoin, pCond)) {
|
||||||
snprintf(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, "l.ts = r.ts is expected in join expression");
|
return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_EXPECTED_TS_EQUAL);
|
||||||
return TSDB_CODE_FAILED;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
|
@ -577,8 +574,7 @@ static int32_t cpdCheckLogicCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin,
|
||||||
|
|
||||||
static int32_t cpdCheckJoinOnCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
|
static int32_t cpdCheckJoinOnCond(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) {
|
||||||
if (NULL == pJoin->pOnConditions) {
|
if (NULL == pJoin->pOnConditions) {
|
||||||
snprintf(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, "not support cross join");
|
return generateUsageErrMsg(pCxt->pPlanCxt->pMsg, pCxt->pPlanCxt->msgLen, TSDB_CODE_PLAN_NOT_SUPPORT_CROSS_JOIN);
|
||||||
return TSDB_CODE_FAILED;
|
|
||||||
}
|
}
|
||||||
if (QUERY_NODE_LOGIC_CONDITION == nodeType(pJoin->pOnConditions)) {
|
if (QUERY_NODE_LOGIC_CONDITION == nodeType(pJoin->pOnConditions)) {
|
||||||
return cpdCheckLogicCond(pCxt, pJoin, (SLogicConditionNode*)pJoin->pOnConditions);
|
return cpdCheckLogicCond(pCxt, pJoin, (SLogicConditionNode*)pJoin->pOnConditions);
|
||||||
|
|
|
@ -1037,6 +1037,9 @@ static int32_t createFillPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren
|
||||||
return TSDB_CODE_OUT_OF_MEMORY;
|
return TSDB_CODE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pFill->mode = pFillNode->mode;
|
||||||
|
pFill->timeRange = pFillNode->timeRange;
|
||||||
|
|
||||||
SDataBlockDescNode* pChildTupe = (((SPhysiNode*)nodesListGetNode(pChildren, 0))->pOutputDataBlockDesc);
|
SDataBlockDescNode* pChildTupe = (((SPhysiNode*)nodesListGetNode(pChildren, 0))->pOutputDataBlockDesc);
|
||||||
int32_t code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pFillNode->node.pTargets, &pFill->pTargets);
|
int32_t code = setListSlotId(pCxt, pChildTupe->dataBlockId, -1, pFillNode->node.pTargets, &pFill->pTargets);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* 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 "planInt.h"
|
||||||
|
|
||||||
|
static char* getUsageErrFormat(int32_t errCode) {
|
||||||
|
switch (errCode) {
|
||||||
|
case TSDB_CODE_PLAN_EXPECTED_TS_EQUAL:
|
||||||
|
return "l.ts = r.ts is expected in join expression";
|
||||||
|
case TSDB_CODE_PLAN_NOT_SUPPORT_CROSS_JOIN:
|
||||||
|
return "not support cross join";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "Unknown error";
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t generateUsageErrMsg(char* pBuf, int32_t len, int32_t errCode, ...) {
|
||||||
|
va_list vArgList;
|
||||||
|
va_start(vArgList, errCode);
|
||||||
|
vsnprintf(pBuf, len, getUsageErrFormat(errCode), vArgList);
|
||||||
|
va_end(vArgList);
|
||||||
|
return errCode;
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* 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
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
*
|
*
|
||||||
|
@ -20,30 +20,32 @@ using namespace std;
|
||||||
|
|
||||||
class PlanBasicTest : public PlannerTestBase {};
|
class PlanBasicTest : public PlannerTestBase {};
|
||||||
|
|
||||||
TEST_F(PlanBasicTest, select) {
|
TEST_F(PlanBasicTest, selectClause) {
|
||||||
useDb("root", "test");
|
useDb("root", "test");
|
||||||
|
|
||||||
run("select * from t1");
|
run("SELECT * FROM t1");
|
||||||
run("select 1 from t1");
|
run("SELECT 1 FROM t1");
|
||||||
run("select * from st1");
|
run("SELECT * FROM st1");
|
||||||
run("select 1 from st1");
|
run("SELECT 1 FROM st1");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PlanBasicTest, where) {
|
TEST_F(PlanBasicTest, whereClause) {
|
||||||
useDb("root", "test");
|
useDb("root", "test");
|
||||||
|
|
||||||
run("select * from t1 where c1 > 10");
|
run("SELECT * FROM t1 WHERE c1 > 10");
|
||||||
|
|
||||||
|
run("SELECT * FROM t1 WHERE ts > TIMESTAMP '2022-04-01 00:00:00' and ts < TIMESTAMP '2022-04-30 23:59:59'");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PlanBasicTest, join) {
|
TEST_F(PlanBasicTest, joinClause) {
|
||||||
useDb("root", "test");
|
useDb("root", "test");
|
||||||
|
|
||||||
run("select t1.c1, t2.c2 from st1s1 t1, st1s2 t2 where t1.ts = t2.ts");
|
run("SELECT t1.c1, t2.c2 FROM st1s1 t1, st1s2 t2 WHERE t1.ts = t2.ts");
|
||||||
run("select t1.c1, t2.c2 from st1s1 t1 join st1s2 t2 on t1.ts = t2.ts");
|
run("SELECT t1.c1, t2.c2 FROM st1s1 t1 JOIN st1s2 t2 ON t1.ts = t2.ts");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PlanBasicTest, func) {
|
TEST_F(PlanBasicTest, func) {
|
||||||
useDb("root", "test");
|
useDb("root", "test");
|
||||||
|
|
||||||
run("select diff(c1) from t1");
|
run("SELECT DIFF(c1) FROM t1");
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,10 @@ TEST_F(PlanIntervalTest, pseudoCol) {
|
||||||
TEST_F(PlanIntervalTest, fill) {
|
TEST_F(PlanIntervalTest, fill) {
|
||||||
useDb("root", "test");
|
useDb("root", "test");
|
||||||
|
|
||||||
run("SELECT COUNT(*) FROM t1 INTERVAL(10s) FILL(LINEAR)");
|
run("SELECT COUNT(*) FROM t1 WHERE ts > TIMESTAMP '2022-04-01 00:00:00' and ts < TIMESTAMP '2022-04-30 23:59:59' "
|
||||||
|
"INTERVAL(10s) FILL(LINEAR)");
|
||||||
|
|
||||||
run("SELECT COUNT(*), sum(c1) FROM t1 INTERVAL(10s) FILL(VALUE, 10, 20)");
|
run("SELECT COUNT(*), SUM(c1) FROM t1 "
|
||||||
|
"WHERE ts > TIMESTAMP '2022-04-01 00:00:00' and ts < TIMESTAMP '2022-04-30 23:59:59' "
|
||||||
|
"INTERVAL(10s) FILL(VALUE, 10, 20)");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue