Merge pull request #14093 from taosdata/feature/3.0_debug_wxy
feat: sql function 'last_row' and sql command 'select constant'
This commit is contained in:
commit
269e9ed505
|
@ -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;
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -757,8 +757,9 @@ boolean_primary(A) ::= NK_LP(C) boolean_value_expression(B) NK_RP(D).
|
||||||
common_expression(A) ::= expression(B). { A = B; }
|
common_expression(A) ::= expression(B). { A = B; }
|
||||||
common_expression(A) ::= boolean_value_expression(B). { A = B; }
|
common_expression(A) ::= boolean_value_expression(B). { A = B; }
|
||||||
|
|
||||||
/************************************************ from_clause *********************************************************/
|
/************************************************ from_clause_opt *********************************************************/
|
||||||
from_clause(A) ::= FROM table_reference_list(B). { A = B; }
|
from_clause_opt(A) ::= . { A = NULL; }
|
||||||
|
from_clause_opt(A) ::= FROM table_reference_list(B). { A = B; }
|
||||||
|
|
||||||
table_reference_list(A) ::= table_reference(B). { A = B; }
|
table_reference_list(A) ::= table_reference(B). { A = B; }
|
||||||
table_reference_list(A) ::= table_reference_list(B) NK_COMMA table_reference(C). { A = createJoinTableNode(pCxt, JOIN_TYPE_INNER, B, C, NULL); }
|
table_reference_list(A) ::= table_reference_list(B) NK_COMMA table_reference(C). { A = createJoinTableNode(pCxt, JOIN_TYPE_INNER, B, C, NULL); }
|
||||||
|
@ -792,9 +793,9 @@ join_type(A) ::= INNER.
|
||||||
|
|
||||||
/************************************************ query_specification *************************************************/
|
/************************************************ query_specification *************************************************/
|
||||||
query_specification(A) ::=
|
query_specification(A) ::=
|
||||||
SELECT set_quantifier_opt(B) select_list(C) from_clause(D) where_clause_opt(E)
|
SELECT set_quantifier_opt(B) select_list(C) from_clause_opt(D)
|
||||||
partition_by_clause_opt(F) range_opt(J) every_opt(K) fill_opt(L) twindow_clause_opt(G)
|
where_clause_opt(E) partition_by_clause_opt(F) range_opt(J) every_opt(K)
|
||||||
group_by_clause_opt(H) having_clause_opt(I). {
|
fill_opt(L) twindow_clause_opt(G) group_by_clause_opt(H) having_clause_opt(I). {
|
||||||
A = createSelectStmt(pCxt, B, C, D);
|
A = createSelectStmt(pCxt, B, C, D);
|
||||||
A = addWhereClause(pCxt, A, E);
|
A = addWhereClause(pCxt, A, E);
|
||||||
A = addPartitionByClause(pCxt, A, F);
|
A = addPartitionByClause(pCxt, A, F);
|
||||||
|
|
|
@ -227,12 +227,16 @@ static int32_t calcConstGroupBy(SCalcConstContext* pCxt, SSelectStmt* pSelect) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DESTORY_LIST(pSelect->pGroupByList);
|
NODES_DESTORY_LIST(pSelect->pGroupByList);
|
||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t calcConstSelect(SCalcConstContext* pCxt, SSelectStmt* pSelect, bool subquery) {
|
static int32_t calcConstSelectWithoutFrom(SCalcConstContext* pCxt, SSelectStmt* pSelect, bool subquery) {
|
||||||
|
return calcConstProjections(pCxt, pSelect, subquery);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t calcConstSelectFrom(SCalcConstContext* pCxt, SSelectStmt* pSelect, bool subquery) {
|
||||||
int32_t code = calcConstFromTable(pCxt, pSelect->pFromTable);
|
int32_t code = calcConstFromTable(pCxt, pSelect->pFromTable);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = calcConstProjections(pCxt, pSelect, subquery);
|
code = calcConstProjections(pCxt, pSelect, subquery);
|
||||||
|
@ -258,6 +262,14 @@ static int32_t calcConstSelect(SCalcConstContext* pCxt, SSelectStmt* pSelect, bo
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t calcConstSelect(SCalcConstContext* pCxt, SSelectStmt* pSelect, bool subquery) {
|
||||||
|
if (NULL == pSelect->pFromTable) {
|
||||||
|
return calcConstSelectWithoutFrom(pCxt, pSelect, subquery);
|
||||||
|
} else {
|
||||||
|
return calcConstSelectFrom(pCxt, pSelect, subquery);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t calcConstDelete(SCalcConstContext* pCxt, SDeleteStmt* pDelete) {
|
static int32_t calcConstDelete(SCalcConstContext* pCxt, SDeleteStmt* pDelete) {
|
||||||
int32_t code = calcConstFromTable(pCxt, pDelete->pFromTable);
|
int32_t code = calcConstFromTable(pCxt, pDelete->pFromTable);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
|
|
@ -689,6 +689,10 @@ static EDealRes translateColumnUseAlias(STranslateContext* pCxt, SColumnNode** p
|
||||||
}
|
}
|
||||||
|
|
||||||
static EDealRes translateColumn(STranslateContext* pCxt, SColumnNode** pCol) {
|
static EDealRes translateColumn(STranslateContext* pCxt, SColumnNode** pCol) {
|
||||||
|
if (NULL != pCxt->pCurrSelectStmt && NULL == pCxt->pCurrSelectStmt->pFromTable) {
|
||||||
|
return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_INVALID_COLUMN, (*pCol)->colName);
|
||||||
|
}
|
||||||
|
|
||||||
// count(*)/first(*)/last(*) and so on
|
// count(*)/first(*)/last(*) and so on
|
||||||
if (0 == strcmp((*pCol)->colName, "*")) {
|
if (0 == strcmp((*pCol)->colName, "*")) {
|
||||||
return DEAL_RES_CONTINUE;
|
return DEAL_RES_CONTINUE;
|
||||||
|
@ -1200,6 +1204,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2489,7 +2494,13 @@ static int32_t replaceOrderByAlias(STranslateContext* pCxt, SNodeList* pProjecti
|
||||||
return pCxt->errCode;
|
return pCxt->errCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t translateSelect(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
static int32_t translateSelectWithoutFrom(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
|
pCxt->pCurrSelectStmt = pSelect;
|
||||||
|
pCxt->currClause = SQL_CLAUSE_SELECT;
|
||||||
|
return translateExprList(pCxt, pSelect->pProjectionList);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t translateSelectFrom(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
pCxt->pCurrSelectStmt = pSelect;
|
pCxt->pCurrSelectStmt = pSelect;
|
||||||
int32_t code = translateFrom(pCxt, pSelect->pFromTable);
|
int32_t code = translateFrom(pCxt, pSelect->pFromTable);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
@ -2538,6 +2549,14 @@ static int32_t translateSelect(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t translateSelect(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||||
|
if (NULL == pSelect->pFromTable) {
|
||||||
|
return translateSelectWithoutFrom(pCxt, pSelect);
|
||||||
|
} else {
|
||||||
|
return translateSelectFrom(pCxt, pSelect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static SNode* createSetOperProject(const char* pTableAlias, SNode* pNode) {
|
static SNode* createSetOperProject(const char* pTableAlias, SNode* pNode) {
|
||||||
SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN);
|
SColumnNode* pCol = (SColumnNode*)nodesMakeNode(QUERY_NODE_COLUMN);
|
||||||
if (NULL == pCol) {
|
if (NULL == pCol) {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -388,4 +388,10 @@ TEST_F(ParserSelectTest, informationSchema) {
|
||||||
run("SELECT * FROM information_schema.user_databases WHERE name = 'information_schema'");
|
run("SELECT * FROM information_schema.user_databases WHERE name = 'information_schema'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserSelectTest, withoutFrom) {
|
||||||
|
useDb("root", "test");
|
||||||
|
|
||||||
|
run("SELECT 1");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ParserTest
|
} // namespace ParserTest
|
||||||
|
|
|
@ -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:
|
||||||
|
@ -844,7 +901,12 @@ static int32_t createDistinctLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSe
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t createSelectLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SLogicNode** pLogicNode) {
|
static int32_t createSelectWithoutFromLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect,
|
||||||
|
SLogicNode** pLogicNode) {
|
||||||
|
return createProjectLogicNode(pCxt, pSelect, pLogicNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t createSelectFromLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SLogicNode** pLogicNode) {
|
||||||
SLogicNode* pRoot = NULL;
|
SLogicNode* pRoot = NULL;
|
||||||
int32_t code = createLogicNodeByTable(pCxt, pSelect, pSelect->pFromTable, &pRoot);
|
int32_t code = createLogicNodeByTable(pCxt, pSelect, pSelect->pFromTable, &pRoot);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
@ -884,6 +946,14 @@ static int32_t createSelectLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSele
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t createSelectLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect, SLogicNode** pLogicNode) {
|
||||||
|
if (NULL == pSelect->pFromTable) {
|
||||||
|
return createSelectWithoutFromLogicNode(pCxt, pSelect, pLogicNode);
|
||||||
|
} else {
|
||||||
|
return createSelectFromLogicNode(pCxt, pSelect, pLogicNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t createSetOpRootLogicNode(SLogicPlanContext* pCxt, SSetOperator* pSetOperator, FCreateSetOpLogicNode func,
|
static int32_t createSetOpRootLogicNode(SLogicPlanContext* pCxt, SSetOperator* pSetOperator, FCreateSetOpLogicNode func,
|
||||||
SLogicNode** pRoot) {
|
SLogicNode** pRoot) {
|
||||||
return createRootLogicNode(pCxt, pSetOperator, pSetOperator->precision, (FCreateLogicNode)func, pRoot);
|
return createRootLogicNode(pCxt, pSetOperator, pSetOperator->precision, (FCreateLogicNode)func, pRoot);
|
||||||
|
|
|
@ -293,9 +293,14 @@ static int32_t cpdCondAppend(SNode** pCond, SNode** pAdditionalCond) {
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t cpdCalcTimeRange(SScanLogicNode* pScan, SNode** pPrimaryKeyCond, SNode** pOtherCond) {
|
static int32_t cpdCalcTimeRange(SOptimizeContext* pCxt, SScanLogicNode* pScan, SNode** pPrimaryKeyCond,
|
||||||
|
SNode** pOtherCond) {
|
||||||
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
|
if (pCxt->pPlanCxt->topicQuery || pCxt->pPlanCxt->streamQuery) {
|
||||||
|
code = cpdCondAppend(pOtherCond, pPrimaryKeyCond);
|
||||||
|
} else {
|
||||||
bool isStrict = false;
|
bool isStrict = false;
|
||||||
int32_t code = filterGetTimeRange(*pPrimaryKeyCond, &pScan->scanRange, &isStrict);
|
code = filterGetTimeRange(*pPrimaryKeyCond, &pScan->scanRange, &isStrict);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
if (isStrict) {
|
if (isStrict) {
|
||||||
nodesDestroyNode(*pPrimaryKeyCond);
|
nodesDestroyNode(*pPrimaryKeyCond);
|
||||||
|
@ -304,6 +309,7 @@ static int32_t cpdCalcTimeRange(SScanLogicNode* pScan, SNode** pPrimaryKeyCond,
|
||||||
}
|
}
|
||||||
*pPrimaryKeyCond = NULL;
|
*pPrimaryKeyCond = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,7 +350,7 @@ static int32_t cpdOptimizeScanCondition(SOptimizeContext* pCxt, SScanLogicNode*
|
||||||
SNode* pOtherCond = NULL;
|
SNode* pOtherCond = NULL;
|
||||||
int32_t code = nodesPartitionCond(&pScan->node.pConditions, &pPrimaryKeyCond, &pTagCond, &pOtherCond);
|
int32_t code = nodesPartitionCond(&pScan->node.pConditions, &pPrimaryKeyCond, &pTagCond, &pOtherCond);
|
||||||
if (TSDB_CODE_SUCCESS == code && NULL != pPrimaryKeyCond) {
|
if (TSDB_CODE_SUCCESS == code && NULL != pPrimaryKeyCond) {
|
||||||
code = cpdCalcTimeRange(pScan, &pPrimaryKeyCond, &pOtherCond);
|
code = cpdCalcTimeRange(pCxt, pScan, &pPrimaryKeyCond, &pOtherCond);
|
||||||
}
|
}
|
||||||
if (TSDB_CODE_SUCCESS == code && NULL != pTagCond) {
|
if (TSDB_CODE_SUCCESS == code && NULL != pTagCond) {
|
||||||
code = cpdApplyTagIndex(pScan, &pTagCond, &pOtherCond);
|
code = cpdApplyTagIndex(pScan, &pTagCond, &pOtherCond);
|
||||||
|
@ -1126,7 +1132,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;
|
||||||
}
|
}
|
||||||
|
@ -914,8 +917,16 @@ static int32_t createProjectPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChild
|
||||||
pProject->slimit = pProjectLogicNode->slimit;
|
pProject->slimit = pProjectLogicNode->slimit;
|
||||||
pProject->soffset = pProjectLogicNode->soffset;
|
pProject->soffset = pProjectLogicNode->soffset;
|
||||||
|
|
||||||
int32_t code = setListSlotId(pCxt, ((SPhysiNode*)nodesListGetNode(pChildren, 0))->pOutputDataBlockDesc->dataBlockId,
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
-1, pProjectLogicNode->pProjections, &pProject->pProjections);
|
if (0 == LIST_LENGTH(pChildren)) {
|
||||||
|
pProject->pProjections = nodesCloneList(pProjectLogicNode->pProjections);
|
||||||
|
if (NULL == pProject->pProjections) {
|
||||||
|
code = TSDB_CODE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
code = setListSlotId(pCxt, ((SPhysiNode*)nodesListGetNode(pChildren, 0))->pOutputDataBlockDesc->dataBlockId, -1,
|
||||||
|
pProjectLogicNode->pProjections, &pProject->pProjections);
|
||||||
|
}
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
code = addDataBlockSlotsForProject(pCxt, pProjectLogicNode->stmtName, pProject->pProjections,
|
code = addDataBlockSlotsForProject(pCxt, pProjectLogicNode->stmtName, pProject->pProjections,
|
||||||
pProject->node.pOutputDataBlockDesc);
|
pProject->node.pOutputDataBlockDesc);
|
||||||
|
|
|
@ -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,21 @@ 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PlanBasicTest, withoutFrom) {
|
||||||
|
useDb("root", "test");
|
||||||
|
|
||||||
|
run("SELECT 1");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue