feat: sql function 'last_row'
This commit is contained in:
parent
78caa7e005
commit
45a806f789
|
@ -190,6 +190,7 @@ bool fmIsForbidWindowFunc(int32_t funcId);
|
||||||
bool fmIsForbidGroupByFunc(int32_t funcId);
|
bool fmIsForbidGroupByFunc(int32_t funcId);
|
||||||
bool fmIsIntervalInterpoFunc(int32_t funcId);
|
bool fmIsIntervalInterpoFunc(int32_t funcId);
|
||||||
bool fmIsInterpFunc(int32_t funcId);
|
bool fmIsInterpFunc(int32_t funcId);
|
||||||
|
bool fmIsLastRowFunc(int32_t funcId);
|
||||||
|
|
||||||
int32_t fmGetDistMethod(const SFunctionNode* pFunc, SFunctionNode** pPartialFunc, SFunctionNode** pMergeFunc);
|
int32_t fmGetDistMethod(const SFunctionNode* pFunc, SFunctionNode** pPartialFunc, SFunctionNode** pMergeFunc);
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ extern "C" {
|
||||||
for (SListCell* cell = (NULL != (list) ? (list)->pHead : NULL); \
|
for (SListCell* cell = (NULL != (list) ? (list)->pHead : NULL); \
|
||||||
(NULL != cell ? (node = &(cell->pNode), true) : (node = NULL, false)); cell = cell->pNext)
|
(NULL != cell ? (node = &(cell->pNode), true) : (node = NULL, false)); cell = cell->pNext)
|
||||||
|
|
||||||
#define DESTORY_LIST(list) \
|
#define NODES_DESTORY_LIST(list) \
|
||||||
do { \
|
do { \
|
||||||
nodesDestroyList((list)); \
|
nodesDestroyList((list)); \
|
||||||
(list) = NULL; \
|
(list) = NULL; \
|
||||||
|
@ -219,6 +219,7 @@ typedef enum ENodeType {
|
||||||
QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN,
|
QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN,
|
||||||
QUERY_NODE_PHYSICAL_PLAN_SYSTABLE_SCAN,
|
QUERY_NODE_PHYSICAL_PLAN_SYSTABLE_SCAN,
|
||||||
QUERY_NODE_PHYSICAL_PLAN_BLOCK_DIST_SCAN,
|
QUERY_NODE_PHYSICAL_PLAN_BLOCK_DIST_SCAN,
|
||||||
|
QUERY_NODE_PHYSICAL_PLAN_LAST_ROW_SCAN,
|
||||||
QUERY_NODE_PHYSICAL_PLAN_PROJECT,
|
QUERY_NODE_PHYSICAL_PLAN_PROJECT,
|
||||||
QUERY_NODE_PHYSICAL_PLAN_MERGE_JOIN,
|
QUERY_NODE_PHYSICAL_PLAN_MERGE_JOIN,
|
||||||
QUERY_NODE_PHYSICAL_PLAN_HASH_AGG,
|
QUERY_NODE_PHYSICAL_PLAN_HASH_AGG,
|
||||||
|
|
|
@ -40,7 +40,8 @@ typedef enum EScanType {
|
||||||
SCAN_TYPE_SYSTEM_TABLE,
|
SCAN_TYPE_SYSTEM_TABLE,
|
||||||
SCAN_TYPE_STREAM,
|
SCAN_TYPE_STREAM,
|
||||||
SCAN_TYPE_TABLE_MERGE,
|
SCAN_TYPE_TABLE_MERGE,
|
||||||
SCAN_TYPE_BLOCK_INFO
|
SCAN_TYPE_BLOCK_INFO,
|
||||||
|
SCAN_TYPE_LAST_ROW
|
||||||
} EScanType;
|
} EScanType;
|
||||||
|
|
||||||
typedef struct SScanLogicNode {
|
typedef struct SScanLogicNode {
|
||||||
|
@ -260,6 +261,7 @@ typedef struct SScanPhysiNode {
|
||||||
|
|
||||||
typedef SScanPhysiNode STagScanPhysiNode;
|
typedef SScanPhysiNode STagScanPhysiNode;
|
||||||
typedef SScanPhysiNode SBlockDistScanPhysiNode;
|
typedef SScanPhysiNode SBlockDistScanPhysiNode;
|
||||||
|
typedef SScanPhysiNode SLastRowScanPhysiNode;
|
||||||
|
|
||||||
typedef struct SSystemTableScanPhysiNode {
|
typedef struct SSystemTableScanPhysiNode {
|
||||||
SScanPhysiNode scan;
|
SScanPhysiNode scan;
|
||||||
|
|
|
@ -258,6 +258,7 @@ typedef struct SSelectStmt {
|
||||||
bool hasUniqueFunc;
|
bool hasUniqueFunc;
|
||||||
bool hasTailFunc;
|
bool hasTailFunc;
|
||||||
bool hasInterpFunc;
|
bool hasInterpFunc;
|
||||||
|
bool hasLastRowFunc;
|
||||||
} SSelectStmt;
|
} SSelectStmt;
|
||||||
|
|
||||||
typedef enum ESetOperatorType { SET_OP_TYPE_UNION_ALL = 1, SET_OP_TYPE_UNION } ESetOperatorType;
|
typedef enum ESetOperatorType { SET_OP_TYPE_UNION_ALL = 1, SET_OP_TYPE_UNION } ESetOperatorType;
|
||||||
|
|
|
@ -1799,7 +1799,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
||||||
{
|
{
|
||||||
.name = "last_row",
|
.name = "last_row",
|
||||||
.type = FUNCTION_TYPE_LAST_ROW,
|
.type = FUNCTION_TYPE_LAST_ROW,
|
||||||
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_MULTI_RES_FUNC,
|
.classification = FUNC_MGT_MULTI_RES_FUNC,
|
||||||
.translateFunc = translateLastRow,
|
.translateFunc = translateLastRow,
|
||||||
.getEnvFunc = getMinmaxFuncEnv,
|
.getEnvFunc = getMinmaxFuncEnv,
|
||||||
.initFunc = minmaxFunctionSetup,
|
.initFunc = minmaxFunctionSetup,
|
||||||
|
|
|
@ -186,6 +186,13 @@ bool fmIsInterpFunc(int32_t funcId) {
|
||||||
return FUNCTION_TYPE_INTERP == funcMgtBuiltins[funcId].type;
|
return FUNCTION_TYPE_INTERP == funcMgtBuiltins[funcId].type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool fmIsLastRowFunc(int32_t funcId) {
|
||||||
|
if (funcId < 0 || funcId >= funcMgtBuiltinsNum) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return FUNCTION_TYPE_LAST_ROW == funcMgtBuiltins[funcId].type;
|
||||||
|
}
|
||||||
|
|
||||||
void fmFuncMgtDestroy() {
|
void fmFuncMgtDestroy() {
|
||||||
void* m = gFunMgtService.pFuncNameHashTable;
|
void* m = gFunMgtService.pFuncNameHashTable;
|
||||||
if (m != NULL && atomic_val_compare_exchange_ptr((void**)&gFunMgtService.pFuncNameHashTable, m, 0) == m) {
|
if (m != NULL && atomic_val_compare_exchange_ptr((void**)&gFunMgtService.pFuncNameHashTable, m, 0) == m) {
|
||||||
|
|
|
@ -220,6 +220,8 @@ const char* nodesNodeName(ENodeType type) {
|
||||||
return "PhysiSystemTableScan";
|
return "PhysiSystemTableScan";
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_BLOCK_DIST_SCAN:
|
case QUERY_NODE_PHYSICAL_PLAN_BLOCK_DIST_SCAN:
|
||||||
return "PhysiBlockDistScan";
|
return "PhysiBlockDistScan";
|
||||||
|
case QUERY_NODE_PHYSICAL_PLAN_LAST_ROW_SCAN:
|
||||||
|
return "PhysiLastRowScan";
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_PROJECT:
|
case QUERY_NODE_PHYSICAL_PLAN_PROJECT:
|
||||||
return "PhysiProject";
|
return "PhysiProject";
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_MERGE_JOIN:
|
case QUERY_NODE_PHYSICAL_PLAN_MERGE_JOIN:
|
||||||
|
@ -4105,6 +4107,7 @@ static int32_t specificNodeToJson(const void* pObj, SJson* pJson) {
|
||||||
return logicPlanToJson(pObj, pJson);
|
return logicPlanToJson(pObj, pJson);
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_TAG_SCAN:
|
case QUERY_NODE_PHYSICAL_PLAN_TAG_SCAN:
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_BLOCK_DIST_SCAN:
|
case QUERY_NODE_PHYSICAL_PLAN_BLOCK_DIST_SCAN:
|
||||||
|
case QUERY_NODE_PHYSICAL_PLAN_LAST_ROW_SCAN:
|
||||||
return physiTagScanNodeToJson(pObj, pJson);
|
return physiTagScanNodeToJson(pObj, pJson);
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_TABLE_SCAN:
|
case QUERY_NODE_PHYSICAL_PLAN_TABLE_SCAN:
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_TABLE_MERGE_SCAN:
|
case QUERY_NODE_PHYSICAL_PLAN_TABLE_MERGE_SCAN:
|
||||||
|
@ -4245,6 +4248,7 @@ static int32_t jsonToSpecificNode(const SJson* pJson, void* pObj) {
|
||||||
return jsonToLogicPlan(pJson, pObj);
|
return jsonToLogicPlan(pJson, pObj);
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_TAG_SCAN:
|
case QUERY_NODE_PHYSICAL_PLAN_TAG_SCAN:
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_BLOCK_DIST_SCAN:
|
case QUERY_NODE_PHYSICAL_PLAN_BLOCK_DIST_SCAN:
|
||||||
|
case QUERY_NODE_PHYSICAL_PLAN_LAST_ROW_SCAN:
|
||||||
return jsonToPhysiTagScanNode(pJson, pObj);
|
return jsonToPhysiTagScanNode(pJson, pObj);
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_TABLE_SCAN:
|
case QUERY_NODE_PHYSICAL_PLAN_TABLE_SCAN:
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_TABLE_MERGE_SCAN:
|
case QUERY_NODE_PHYSICAL_PLAN_TABLE_MERGE_SCAN:
|
||||||
|
|
|
@ -273,6 +273,8 @@ SNode* nodesMakeNode(ENodeType type) {
|
||||||
return makeNode(type, sizeof(SSystemTableScanPhysiNode));
|
return makeNode(type, sizeof(SSystemTableScanPhysiNode));
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_BLOCK_DIST_SCAN:
|
case QUERY_NODE_PHYSICAL_PLAN_BLOCK_DIST_SCAN:
|
||||||
return makeNode(type, sizeof(SBlockDistScanPhysiNode));
|
return makeNode(type, sizeof(SBlockDistScanPhysiNode));
|
||||||
|
case QUERY_NODE_PHYSICAL_PLAN_LAST_ROW_SCAN:
|
||||||
|
return makeNode(type, sizeof(SLastRowScanPhysiNode));
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_PROJECT:
|
case QUERY_NODE_PHYSICAL_PLAN_PROJECT:
|
||||||
return makeNode(type, sizeof(SProjectPhysiNode));
|
return makeNode(type, sizeof(SProjectPhysiNode));
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_MERGE_JOIN:
|
case QUERY_NODE_PHYSICAL_PLAN_MERGE_JOIN:
|
||||||
|
@ -781,6 +783,7 @@ void nodesDestroyNode(SNode* pNode) {
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN:
|
case QUERY_NODE_PHYSICAL_PLAN_STREAM_SCAN:
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_SYSTABLE_SCAN:
|
case QUERY_NODE_PHYSICAL_PLAN_SYSTABLE_SCAN:
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_BLOCK_DIST_SCAN:
|
case QUERY_NODE_PHYSICAL_PLAN_BLOCK_DIST_SCAN:
|
||||||
|
case QUERY_NODE_PHYSICAL_PLAN_LAST_ROW_SCAN:
|
||||||
destroyScanPhysiNode((SScanPhysiNode*)pNode);
|
destroyScanPhysiNode((SScanPhysiNode*)pNode);
|
||||||
break;
|
break;
|
||||||
case QUERY_NODE_PHYSICAL_PLAN_PROJECT: {
|
case QUERY_NODE_PHYSICAL_PLAN_PROJECT: {
|
||||||
|
|
|
@ -227,7 +227,7 @@ static int32_t calcConstGroupBy(SCalcConstContext* pCxt, SSelectStmt* pSelect) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DESTORY_LIST(pSelect->pGroupByList);
|
NODES_DESTORY_LIST(pSelect->pGroupByList);
|
||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1176,6 +1176,7 @@ static void setFuncClassification(SSelectStmt* pSelect, SFunctionNode* pFunc) {
|
||||||
pSelect->hasUniqueFunc = pSelect->hasUniqueFunc ? true : (FUNCTION_TYPE_UNIQUE == pFunc->funcType);
|
pSelect->hasUniqueFunc = pSelect->hasUniqueFunc ? true : (FUNCTION_TYPE_UNIQUE == pFunc->funcType);
|
||||||
pSelect->hasTailFunc = pSelect->hasTailFunc ? true : (FUNCTION_TYPE_TAIL == pFunc->funcType);
|
pSelect->hasTailFunc = pSelect->hasTailFunc ? true : (FUNCTION_TYPE_TAIL == pFunc->funcType);
|
||||||
pSelect->hasInterpFunc = pSelect->hasInterpFunc ? true : (FUNCTION_TYPE_INTERP == pFunc->funcType);
|
pSelect->hasInterpFunc = pSelect->hasInterpFunc ? true : (FUNCTION_TYPE_INTERP == pFunc->funcType);
|
||||||
|
pSelect->hasLastRowFunc = pSelect->hasLastRowFunc ? true : (FUNCTION_TYPE_LAST_ROW == pFunc->funcType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -296,6 +296,59 @@ static int32_t createScanLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t createColumnByLastRow(SNodeList* pFuncs, SNodeList** pOutput) {
|
||||||
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
|
SNodeList* pCols = NULL;
|
||||||
|
SNode* pFunc = NULL;
|
||||||
|
FOREACH(pFunc, pFuncs) {
|
||||||
|
SFunctionNode* pLastRow = (SFunctionNode*)pFunc;
|
||||||
|
SColumnNode* pCol = (SColumnNode*)nodesListGetNode(pLastRow->pParameterList, 0);
|
||||||
|
snprintf(pCol->colName, sizeof(pCol->colName), "%s", pLastRow->node.aliasName);
|
||||||
|
snprintf(pCol->node.aliasName, sizeof(pCol->colName), "%s", pLastRow->node.aliasName);
|
||||||
|
NODES_CLEAR_LIST(pLastRow->pParameterList);
|
||||||
|
code = nodesListMakeStrictAppend(&pCols, (SNode*)pCol);
|
||||||
|
if (TSDB_CODE_SUCCESS != code) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
*pOutput = pCols;
|
||||||
|
} else {
|
||||||
|
nodesDestroyList(pCols);
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t createLastRowScanLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SRealTableNode* pRealTable,
|
||||||
|
SLogicNode** pLogicNode) {
|
||||||
|
SScanLogicNode* pScan = NULL;
|
||||||
|
int32_t code = makeScanLogicNode(pCxt, pRealTable, false, (SLogicNode**)&pScan);
|
||||||
|
|
||||||
|
SNodeList* pFuncs = NULL;
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
pScan->scanType = SCAN_TYPE_LAST_ROW;
|
||||||
|
code = nodesCollectFuncs(pSelect, SQL_CLAUSE_FROM, fmIsLastRowFunc, &pFuncs);
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = rewriteExprsForSelect(pFuncs, pSelect, SQL_CLAUSE_FROM);
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = createColumnByLastRow(pFuncs, &pScan->pScanCols);
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = createColumnByRewriteExprs(pScan->pScanCols, &pScan->node.pTargets);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
*pLogicNode = (SLogicNode*)pScan;
|
||||||
|
} else {
|
||||||
|
nodesDestroyNode((SNode*)pScan);
|
||||||
|
}
|
||||||
|
nodesDestroyList(pFuncs);
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t createSubqueryLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, STempTableNode* pTable,
|
static int32_t createSubqueryLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, STempTableNode* pTable,
|
||||||
SLogicNode** pLogicNode) {
|
SLogicNode** pLogicNode) {
|
||||||
return createQueryLogicNode(pCxt, pTable->pSubquery, pLogicNode);
|
return createQueryLogicNode(pCxt, pTable->pSubquery, pLogicNode);
|
||||||
|
@ -367,7 +420,11 @@ static int32_t doCreateLogicNodeByTable(SLogicPlanContext* pCxt, SSelectStmt* pS
|
||||||
SLogicNode** pLogicNode) {
|
SLogicNode** pLogicNode) {
|
||||||
switch (nodeType(pTable)) {
|
switch (nodeType(pTable)) {
|
||||||
case QUERY_NODE_REAL_TABLE:
|
case QUERY_NODE_REAL_TABLE:
|
||||||
|
if (pSelect->hasLastRowFunc) {
|
||||||
|
return createLastRowScanLogicNode(pCxt, pSelect, (SRealTableNode*)pTable, pLogicNode);
|
||||||
|
} else {
|
||||||
return createScanLogicNode(pCxt, pSelect, (SRealTableNode*)pTable, pLogicNode);
|
return createScanLogicNode(pCxt, pSelect, (SRealTableNode*)pTable, pLogicNode);
|
||||||
|
}
|
||||||
case QUERY_NODE_TEMP_TABLE:
|
case QUERY_NODE_TEMP_TABLE:
|
||||||
return createSubqueryLogicNode(pCxt, pSelect, (STempTableNode*)pTable, pLogicNode);
|
return createSubqueryLogicNode(pCxt, pSelect, (STempTableNode*)pTable, pLogicNode);
|
||||||
case QUERY_NODE_JOIN_TABLE:
|
case QUERY_NODE_JOIN_TABLE:
|
||||||
|
|
|
@ -1126,7 +1126,7 @@ static int32_t partTagsOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSub
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DESTORY_LIST(((SAggLogicNode*)pNode)->pGroupKeys);
|
NODES_DESTORY_LIST(((SAggLogicNode*)pNode)->pGroupKeys);
|
||||||
}
|
}
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = partTagsOptRebuildTbanme(pScan->pPartTags);
|
code = partTagsOptRebuildTbanme(pScan->pPartTags);
|
||||||
|
|
|
@ -462,6 +462,8 @@ static ENodeType getScanOperatorType(EScanType scanType) {
|
||||||
return QUERY_NODE_PHYSICAL_PLAN_TABLE_MERGE_SCAN;
|
return QUERY_NODE_PHYSICAL_PLAN_TABLE_MERGE_SCAN;
|
||||||
case SCAN_TYPE_BLOCK_INFO:
|
case SCAN_TYPE_BLOCK_INFO:
|
||||||
return QUERY_NODE_PHYSICAL_PLAN_BLOCK_DIST_SCAN;
|
return QUERY_NODE_PHYSICAL_PLAN_BLOCK_DIST_SCAN;
|
||||||
|
case SCAN_TYPE_LAST_ROW:
|
||||||
|
return QUERY_NODE_PHYSICAL_PLAN_LAST_ROW_SCAN;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -559,6 +561,7 @@ static int32_t createScanPhysiNode(SPhysiPlanContext* pCxt, SSubplan* pSubplan,
|
||||||
switch (pScanLogicNode->scanType) {
|
switch (pScanLogicNode->scanType) {
|
||||||
case SCAN_TYPE_TAG:
|
case SCAN_TYPE_TAG:
|
||||||
case SCAN_TYPE_BLOCK_INFO:
|
case SCAN_TYPE_BLOCK_INFO:
|
||||||
|
case SCAN_TYPE_LAST_ROW:
|
||||||
return createSimpleScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode);
|
return createSimpleScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode);
|
||||||
case SCAN_TYPE_TABLE:
|
case SCAN_TYPE_TABLE:
|
||||||
return createTableScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode);
|
return createTableScanPhysiNode(pCxt, pSubplan, pScanLogicNode, pPhyNode);
|
||||||
|
@ -732,7 +735,7 @@ static int32_t rewritePrecalcExprs(SPhysiPlanContext* pCxt, SNodeList* pList, SN
|
||||||
SRewritePrecalcExprsCxt cxt = {.errCode = TSDB_CODE_SUCCESS, .pPrecalcExprs = *pPrecalcExprs};
|
SRewritePrecalcExprsCxt cxt = {.errCode = TSDB_CODE_SUCCESS, .pPrecalcExprs = *pPrecalcExprs};
|
||||||
nodesRewriteExprs(*pRewrittenList, doRewritePrecalcExprs, &cxt);
|
nodesRewriteExprs(*pRewrittenList, doRewritePrecalcExprs, &cxt);
|
||||||
if (0 == LIST_LENGTH(cxt.pPrecalcExprs) || TSDB_CODE_SUCCESS != cxt.errCode) {
|
if (0 == LIST_LENGTH(cxt.pPrecalcExprs) || TSDB_CODE_SUCCESS != cxt.errCode) {
|
||||||
DESTORY_LIST(*pPrecalcExprs);
|
NODES_DESTORY_LIST(*pPrecalcExprs);
|
||||||
}
|
}
|
||||||
return cxt.errCode;
|
return cxt.errCode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -934,7 +934,7 @@ static int32_t unionSplitSubplan(SSplitContext* pCxt, SLogicSubplan* pUnionSubpl
|
||||||
}
|
}
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
nodesDestroyList(pSubplanChildren);
|
nodesDestroyList(pSubplanChildren);
|
||||||
DESTORY_LIST(pSplitNode->pChildren);
|
NODES_DESTORY_LIST(pSplitNode->pChildren);
|
||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,3 +83,15 @@ TEST_F(PlanBasicTest, interpFunc) {
|
||||||
|
|
||||||
run("SELECT INTERP(c1) FROM t1 RANGE('2017-7-14 18:00:00', '2017-7-14 19:00:00') EVERY(5s) FILL(LINEAR)");
|
run("SELECT INTERP(c1) FROM t1 RANGE('2017-7-14 18:00:00', '2017-7-14 19:00:00') EVERY(5s) FILL(LINEAR)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(PlanBasicTest, lastRowFunc) {
|
||||||
|
useDb("root", "test");
|
||||||
|
|
||||||
|
run("SELECT LAST_ROW(c1) FROM t1");
|
||||||
|
|
||||||
|
run("SELECT LAST_ROW(*) FROM t1");
|
||||||
|
|
||||||
|
run("SELECT LAST_ROW(c1, c2) FROM t1");
|
||||||
|
|
||||||
|
run("SELECT LAST_ROW(c1) FROM st1");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue