diff --git a/include/util/tdef.h b/include/util/tdef.h index 2b0aa00b1a..c07a2299d0 100644 --- a/include/util/tdef.h +++ b/include/util/tdef.h @@ -562,6 +562,7 @@ typedef enum ELogicConditionType { #define TSDB_QUERY_CLEAR_TYPE(x, _type) ((x) &= (~_type)) #define TSDB_QUERY_RESET_TYPE(x) ((x) = TSDB_QUERY_TYPE_NON_TYPE) +#define TSDB_ORDER_NONE 0 #define TSDB_ORDER_ASC 1 #define TSDB_ORDER_DESC 2 diff --git a/source/common/src/tglobal.c b/source/common/src/tglobal.c index 24fc3b2a96..68ea3f4a42 100644 --- a/source/common/src/tglobal.c +++ b/source/common/src/tglobal.c @@ -2757,6 +2757,7 @@ static int32_t taosCfgDynamicOptionsForClient(SConfig *pCfg, const char *name) { {"tsmaDataDeleteMark", &tsmaDataDeleteMark}, {"numOfRpcSessions", &tsNumOfRpcSessions}, {"bypassFlag", &tsBypassFlag}, + {"safetyCheckLevel", &tsSafetyCheckLevel}, {"streamCoverage", &tsStreamCoverage}}; if ((code = taosCfgSetOption(debugOptions, tListLen(debugOptions), pItem, true)) != TSDB_CODE_SUCCESS) { diff --git a/source/libs/planner/inc/planInt.h b/source/libs/planner/inc/planInt.h index 59e771454c..57cd949138 100644 --- a/source/libs/planner/inc/planInt.h +++ b/source/libs/planner/inc/planInt.h @@ -70,6 +70,7 @@ bool isPartTagAgg(SAggLogicNode* pAgg); bool isPartTableWinodw(SWindowLogicNode* pWindow); bool keysHasCol(SNodeList* pKeys); bool keysHasTbname(SNodeList* pKeys); +bool projectCouldMergeUnsortDataBlock(SProjectLogicNode* pProject); SFunctionNode* createGroupKeyAggFunc(SColumnNode* pGroupCol); int32_t getTimeRangeFromNode(SNode** pPrimaryKeyCond, STimeWindow* pTimeRange, bool* pIsStrict); int32_t tagScanSetExecutionMode(SScanLogicNode* pScan); diff --git a/source/libs/planner/src/planLogicCreater.c b/source/libs/planner/src/planLogicCreater.c index 363aa71479..c3fd9cdcf2 100644 --- a/source/libs/planner/src/planLogicCreater.c +++ b/source/libs/planner/src/planLogicCreater.c @@ -412,7 +412,7 @@ static int32_t createScanLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect int32_t code = makeScanLogicNode(pCxt, pRealTable, pSelect->hasRepeatScanFuncs, (SLogicNode**)&pScan); pScan->node.groupAction = GROUP_ACTION_NONE; - pScan->node.resultDataOrder = DATA_ORDER_LEVEL_IN_BLOCK; + pScan->node.resultDataOrder = (pRealTable->pMeta->tableType == TSDB_SUPER_TABLE) ? DATA_ORDER_LEVEL_IN_BLOCK : DATA_ORDER_LEVEL_GLOBAL; if (pCxt->pPlanCxt->streamQuery) { pScan->triggerType = pCxt->pPlanCxt->triggerType; pScan->watermark = pCxt->pPlanCxt->watermark; diff --git a/source/libs/planner/src/planOptimizer.c b/source/libs/planner/src/planOptimizer.c index 7085c8dc7c..b9f5d42604 100644 --- a/source/libs/planner/src/planOptimizer.c +++ b/source/libs/planner/src/planOptimizer.c @@ -223,6 +223,13 @@ static void optSetParentOrder(SLogicNode* pNode, EOrder order, SLogicNode* pNode // Use window output ts order instead. order = pNode->outputTsOrder; break; + case QUERY_NODE_LOGIC_PLAN_PROJECT: + if (projectCouldMergeUnsortDataBlock((SProjectLogicNode*)pNode)) { + pNode->outputTsOrder = TSDB_ORDER_NONE; + return; + } + pNode->outputTsOrder = order; + break; default: pNode->outputTsOrder = order; break; diff --git a/source/libs/planner/src/planPhysiCreater.c b/source/libs/planner/src/planPhysiCreater.c index c60024b323..31d51fad9b 100644 --- a/source/libs/planner/src/planPhysiCreater.c +++ b/source/libs/planner/src/planPhysiCreater.c @@ -2053,6 +2053,23 @@ static bool projectCanMergeDataBlock(SProjectLogicNode* pProject) { return DATA_ORDER_LEVEL_GLOBAL == pChild->resultDataOrder ? true : false; } +bool projectCouldMergeUnsortDataBlock(SProjectLogicNode* pProject) { + SLogicNode* pChild = (SLogicNode*)nodesListGetNode(pProject->node.pChildren, 0); + if (DATA_ORDER_LEVEL_GLOBAL == pChild->resultDataOrder) { + return false; + } + if (GROUP_ACTION_KEEP == pProject->node.groupAction) { + return false; + } + if (DATA_ORDER_LEVEL_NONE == pProject->node.resultDataOrder) { + return true; + } + if (1 != LIST_LENGTH(pProject->node.pChildren)) { + return true; + } + return false; +} + static int32_t createProjectPhysiNode(SPhysiPlanContext* pCxt, SNodeList* pChildren, SProjectLogicNode* pProjectLogicNode, SPhysiNode** pPhyNode) { SProjectPhysiNode* pProject = diff --git a/tests/system-test/2-query/last_row.py b/tests/system-test/2-query/last_row.py index 1534183056..dd510459b6 100644 --- a/tests/system-test/2-query/last_row.py +++ b/tests/system-test/2-query/last_row.py @@ -353,6 +353,13 @@ class TDTestCase: tdSql.checkData(0, 2, -999) tdSql.checkData(0, 3, None) tdSql.checkData(0, 4,-9.99000) + + tdSql.query(f"select last_row(c1), c2, c3 , c4, c5 from (select * from {dbname}.ct1)") + tdSql.checkData(0, 0, 9) + tdSql.checkData(0, 1, -99999) + tdSql.checkData(0, 2, -999) + tdSql.checkData(0, 3, None) + tdSql.checkData(0, 4,-9.99000) # bug need fix tdSql.query(f"select last_row(c1), c2, c3 , c4, c5 from {dbname}.stb1 where tbname='ct1'") @@ -477,6 +484,11 @@ class TDTestCase: tdSql.checkData(0,1,33333) tdSql.checkData(0,2,333) tdSql.checkData(0,3,3) + tdSql.query(f"select last_row(abs(floor(t1)) ,t2 ,ceil(abs(t3)) , abs(ceil(t4)) ) from (select * from {dbname}.stb1)") + tdSql.checkData(0,0,3) + tdSql.checkData(0,1,33333) + tdSql.checkData(0,2,333) + tdSql.checkData(0,3,3) # filter by tag tdSql.query(f"select tbname ,last_row(c1) from {dbname}.stb1 where t1 =0 ") @@ -912,6 +924,70 @@ class TDTestCase: tdSql.checkData(0 , 1 , None) tdSql.checkData(0 , 2 , None) + def lastrow_in_subquery(self, dbname="db"): + tdSql.execute(f'create database if not exists {dbname};') + tdSql.execute(f'use {dbname}') + tdSql.execute(f'drop table if exists {dbname}.meters') + + tdSql.execute(f'create table {dbname}.meters (ts timestamp, c0 int, c1 float, c2 nchar(30), c3 bool) tags (t1 nchar(30))') + tdSql.execute(f'create table {dbname}.d0 using {dbname}.meters tags("st1")') + tdSql.execute(f'create table {dbname}.d1 using {dbname}.meters tags("st2")') + tdSql.execute(f'insert into {dbname}.d0 values(1734574929000, 1, 1, "c2", true)') + tdSql.execute(f'insert into {dbname}.d0 values(1734574929001, 2, 2, "bbbbbbbbb1", false)') + tdSql.execute(f'insert into {dbname}.d0 values(1734574929002, 2, 2, "bbbbbbbbb1", false)') + tdSql.execute(f'insert into {dbname}.d0 values(1734574929003, 3, 3, "a2", true)') + tdSql.execute(f'insert into {dbname}.d0 values(1734574929004, 4, 4, "bbbbbbbbb2", false)') + + tdSql.execute(f'insert into {dbname}.d1 values(1734574929000, 1, 1, "c2", true)') + + tdSql.execute(f'use {dbname}') + tdSql.execute(f'Create table {dbname}.normal_table (ts timestamp, c0 int, c1 float, c2 nchar(30), c3 bool)') + tdSql.execute(f'insert into {dbname}.normal_table (select * from {dbname}.d0)') + + tdSql.query(f'select count(1), last(ts), last_row(c0) from (select * from {dbname}.meters)') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 6) + tdSql.checkData(0, 1, 1734574929004) + tdSql.checkData(0, 2, 4) + tdSql.query(f'select count(1), last(ts), last_row(c0) from (select * from {dbname}.meters order by ts desc)') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 6) + tdSql.checkData(0, 1, 1734574929004) + tdSql.checkData(0, 2, 4) + tdSql.query(f'select count(1), last(ts), last_row(c0) from (select * from {dbname}.meters order by ts asc)') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 6) + tdSql.checkData(0, 1, 1734574929004) + tdSql.checkData(0, 2, 4) + tdSql.query(f'select count(1), last(ts), last_row(c0) from (select * from {dbname}.meters order by c0 asc)') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 6) + tdSql.checkData(0, 1, 1734574929004) + tdSql.checkData(0, 2, 4) + tdSql.query(f'select count(1), last_row(ts), last_row(c0) from (select * from {dbname}.meters)') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 6) + tdSql.checkData(0, 1, 1734574929004) + tdSql.checkData(0, 2, 4) + tdSql.query(f'select tbname, last_row(ts), last_row(c0) from (select *, tbname from {dbname}.meters) group by tbname order by tbname') + tdSql.checkRows(2) + tdSql.checkData(0, 0, 'd0') + tdSql.checkData(0, 1, 1734574929004) + tdSql.checkData(0, 2, 4) + tdSql.checkData(1, 0, 'd1') + tdSql.checkData(1, 1, 1734574929000) + tdSql.checkData(1, 2, 1) + tdSql.query(f'select count(1), last_row(ts), last_row(c0) from (select * from {dbname}.d0)') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 5) + tdSql.checkData(0, 1, 1734574929004) + tdSql.checkData(0, 2, 4) + tdSql.query(f'select count(1), last_row(ts), last_row(c0) from (select * from {dbname}.normal_table)') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 5) + tdSql.checkData(0, 1, 1734574929004) + tdSql.checkData(0, 2, 4) + def run(self): # sourcery skip: extract-duplicate-method, remove-redundant-fstring # tdSql.prepare() @@ -944,6 +1020,8 @@ class TDTestCase: self.basic_query() self.lastRowDelayTest("DELAYTEST") + + self.lastrow_in_subquery("db1") def stop(self):