From e55b7c52d8362e50917a1a6d4f7a9369e3973561 Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Thu, 14 Dec 2023 17:06:19 +0800 Subject: [PATCH] fix: add left join case --- source/common/src/tdatablock.c | 19 ++-- source/libs/executor/inc/mergejoin.h | 13 ++- source/libs/executor/src/mergejoinoperator.c | 104 +++++++++++++------ source/libs/planner/src/planOptimizer.c | 26 ++--- tests/script/tsim/join/join.sim | 69 ++++++++++++ tests/script/tsim/join/left_join.sim | 96 +++++++++++++++++ 6 files changed, 270 insertions(+), 57 deletions(-) create mode 100644 tests/script/tsim/join/join.sim create mode 100644 tests/script/tsim/join/left_join.sim diff --git a/source/common/src/tdatablock.c b/source/common/src/tdatablock.c index a3fc95f4db..a09680599b 100644 --- a/source/common/src/tdatablock.c +++ b/source/common/src/tdatablock.c @@ -191,26 +191,29 @@ static int32_t doCopyNItems(struct SColumnInfoData* pColumnInfoData, int32_t cur } size_t start = 1; - - // the first item - memcpy(pColumnInfoData->pData, pData, itemLen); - int32_t t = 0; int32_t count = log(numOfRows) / log(2); + uint32_t startOffset = (IS_VAR_DATA_TYPE(pColumnInfoData->info.type)) ? pColumnInfoData->varmeta.length : (currentRow * itemLen); + + // the first item + memcpy(pColumnInfoData->pData + startOffset, pData, itemLen); + while (t < count) { int32_t xlen = 1 << t; - memcpy(pColumnInfoData->pData + start * itemLen + pColumnInfoData->varmeta.length, pColumnInfoData->pData, + memcpy(pColumnInfoData->pData + start * itemLen + startOffset, + pColumnInfoData->pData + startOffset, xlen * itemLen); t += 1; start += xlen; } - + // the tail part if (numOfRows > start) { - memcpy(pColumnInfoData->pData + start * itemLen + currentRow * itemLen, pColumnInfoData->pData, + memcpy(pColumnInfoData->pData + start * itemLen + startOffset, + pColumnInfoData->pData + startOffset, (numOfRows - start) * itemLen); } - + if (IS_VAR_DATA_TYPE(pColumnInfoData->info.type)) { for (int32_t i = 0; i < numOfRows; ++i) { pColumnInfoData->varmeta.offset[i + currentRow] = pColumnInfoData->varmeta.length + i * itemLen; diff --git a/source/libs/executor/inc/mergejoin.h b/source/libs/executor/inc/mergejoin.h index 91706bd87a..bbc5ef3d13 100755 --- a/source/libs/executor/inc/mergejoin.h +++ b/source/libs/executor/inc/mergejoin.h @@ -191,15 +191,18 @@ typedef struct SMJoinOperatorInfo { #define GRP_REMAIN_ROWS(_grp) ((_grp)->endIdx - (_grp)->readIdx + 1) #define GRP_DONE(_grp) ((_grp)->readIdx > (_grp)->endIdx) -#define MJOIN_TB_ROWS_DONE(_tb) ((_tb)->blkRowIdx >= (_tb)->blk->info.rows) +#define MJOIN_PROBE_TB_ROWS_DONE(_tb) ((_tb)->blkRowIdx >= (_tb)->blk->info.rows) +#define MJOIN_BUILD_TB_ROWS_DONE(_tb) ((NULL == (_tb)->blk) || ((_tb)->blkRowIdx >= (_tb)->blk->info.rows)) #define BLK_IS_FULL(_blk) ((_blk)->info.rows == (_blk)->info.capacity) -#define MJOIN_GET_TB_COL_TS(_col, _ts, _tb) \ - do { \ - (_col) = taosArrayGet((_tb)->blk->pDataBlock, (_tb)->primCol->srcSlot); \ - (_ts) = *((int64_t*)(_col)->pData + (_tb)->blkRowIdx); \ +#define MJOIN_GET_TB_COL_TS(_col, _ts, _tb) \ + do { \ + if (NULL != (_tb)->blk) { \ + (_col) = taosArrayGet((_tb)->blk->pDataBlock, (_tb)->primCol->srcSlot); \ + (_ts) = *((int64_t*)(_col)->pData + (_tb)->blkRowIdx); \ + } \ } while (0) #define MJOIN_GET_TB_CUR_TS(_col, _ts, _tb) \ diff --git a/source/libs/executor/src/mergejoinoperator.c b/source/libs/executor/src/mergejoinoperator.c index e4019bb742..b382821691 100644 --- a/source/libs/executor/src/mergejoinoperator.c +++ b/source/libs/executor/src/mergejoinoperator.c @@ -61,28 +61,37 @@ static int32_t mJoinInitPrimKeyInfo(SMJoinTableCtx* pTable, int32_t slotId) { return TSDB_CODE_SUCCESS; } -static int32_t mJoinInitKeyColsInfo(SMJoinTableCtx* pTable, SNodeList* pList) { - pTable->keyNum = LIST_LENGTH(pList); +static int32_t mJoinInitColsInfo(int32_t* colNum, int64_t* rowSize, SMJoinColInfo** pCols, SNodeList* pList) { + *colNum = LIST_LENGTH(pList); - pTable->keyCols = taosMemoryMalloc(pTable->keyNum * sizeof(SMJoinColInfo)); - if (NULL == pTable->keyCols) { + *pCols = taosMemoryMalloc((*colNum) * sizeof(SMJoinColInfo)); + if (NULL == *pCols) { return TSDB_CODE_OUT_OF_MEMORY; } - int64_t bufSize = 0; + *rowSize = 0; + int32_t i = 0; SNode* pNode = NULL; FOREACH(pNode, pList) { SColumnNode* pColNode = (SColumnNode*)pNode; - pTable->keyCols[i].srcSlot = pColNode->slotId; - pTable->keyCols[i].vardata = IS_VAR_DATA_TYPE(pColNode->node.resType.type); - pTable->keyCols[i].bytes = pColNode->node.resType.bytes; - bufSize += pColNode->node.resType.bytes; + (*pCols)[i].srcSlot = pColNode->slotId; + (*pCols)[i].vardata = IS_VAR_DATA_TYPE(pColNode->node.resType.type); + (*pCols)[i].bytes = pColNode->node.resType.bytes; + *rowSize += pColNode->node.resType.bytes; ++i; } + return TSDB_CODE_SUCCESS; +} + + +static int32_t mJoinInitKeyColsInfo(SMJoinTableCtx* pTable, SNodeList* pList) { + int64_t rowSize = 0; + MJ_ERR_RET(mJoinInitColsInfo(&pTable->keyNum, &rowSize, &pTable->keyCols, pList)); + if (pTable->keyNum > 1) { - pTable->keyBuf = taosMemoryMalloc(bufSize); + pTable->keyBuf = taosMemoryMalloc(rowSize); if (NULL == pTable->keyBuf) { return TSDB_CODE_OUT_OF_MEMORY; } @@ -91,27 +100,44 @@ static int32_t mJoinInitKeyColsInfo(SMJoinTableCtx* pTable, SNodeList* pList) { return TSDB_CODE_SUCCESS; } + +static int32_t mJoinInitColsMap(int32_t* colNum, SMJoinColMap** pCols, int32_t blkId, SNodeList* pList) { + *pCols = taosMemoryMalloc(LIST_LENGTH(pList) * sizeof(SMJoinColMap)); + if (NULL == *pCols) { + return TSDB_CODE_OUT_OF_MEMORY; + } + + int32_t i = 0; + SNode* pNode = NULL; + FOREACH(pNode, pList) { + STargetNode* pTarget = (STargetNode*)pNode; + SColumnNode* pColumn = (SColumnNode*)pTarget->pExpr; + if (pColumn->dataBlockId == blkId) { + (*pCols)[i].srcSlot = pColumn->slotId; + (*pCols)[i].dstSlot = pTarget->slotId; + ++i; + } + } + + *colNum = i; + + return TSDB_CODE_SUCCESS; +} + static int32_t mJoinInitTableInfo(SMJoinOperatorInfo* pJoin, SSortMergeJoinPhysiNode* pJoinNode, SOperatorInfo** pDownstream, int32_t idx, SQueryStat* pStat) { SMJoinTableCtx* pTable = &pJoin->tbs[idx]; pTable->downStream = pDownstream[idx]; pTable->blkId = pDownstream[idx]->resultDataBlockId; - int32_t code = mJoinInitPrimKeyInfo(pTable, (0 == idx) ? pJoinNode->leftPrimSlotId : pJoinNode->rightPrimSlotId); - if (code) { - return code; - } - code = mJoinInitKeyColsInfo(pTable, (0 == idx) ? pJoinNode->pEqLeft : pJoinNode->pEqRight); - if (code) { - return code; - } -/* - code = mJoinInitValColsInfo(pTable, pJoinNode->pTargets); - if (code) { - return code; - } -*/ + MJ_ERR_RET(mJoinInitPrimKeyInfo(pTable, (0 == idx) ? pJoinNode->leftPrimSlotId : pJoinNode->rightPrimSlotId)); + + MJ_ERR_RET(mJoinInitKeyColsInfo(pTable, (0 == idx) ? pJoinNode->pEqLeft : pJoinNode->pEqRight)); + MJ_ERR_RET(mJoinInitColsMap(&pTable->finNum, &pTable->finCols, pTable->blkId, pJoinNode->pTargets)); + memcpy(&pTable->inputStat, pStat, sizeof(*pStat)); pTable->eqGrps = taosArrayInit(8, sizeof(SMJoinGrpRows)); + taosArrayReserve(pTable->eqGrps, 1); + if (E_JOIN_TB_BUILD == pTable->type) { pTable->createdBlks = taosArrayInit(8, POINTER_BYTES); pTable->pGrpArrays = taosArrayInit(32, POINTER_BYTES); @@ -167,6 +193,7 @@ static void mJoinSetBuildAndProbeTable(SMJoinOperatorInfo* pInfo, SSortMergeJoin static int32_t mJoinInitMergeCtx(SMJoinOperatorInfo* pJoin, SSortMergeJoinPhysiNode* pJoinNode) { SMJoinMergeCtx* pCtx = &pJoin->ctx.mergeCtx; + pCtx->pJoin = pJoin; pCtx->lastEqTs = INT64_MIN; pCtx->hashCan = pJoin->probe->keyNum > 0; @@ -984,14 +1011,14 @@ static SSDataBlock* mLeftJoinDo(struct SOperatorInfo* pOperator) { return pCtx->finBlk; } - if (MJOIN_TB_ROWS_DONE(pJoin->probe)) { + if (MJOIN_PROBE_TB_ROWS_DONE(pJoin->probe)) { continue; } else { MJOIN_GET_TB_CUR_TS(pProbeCol, probeTs, pJoin->probe); } } - while (!MJOIN_TB_ROWS_DONE(pJoin->probe) && !MJOIN_TB_ROWS_DONE(pJoin->build)) { + while (!MJOIN_PROBE_TB_ROWS_DONE(pJoin->probe) && !MJOIN_BUILD_TB_ROWS_DONE(pJoin->build)) { if (probeTs == buildTs) { pCtx->lastEqTs = probeTs; MJ_ERR_JRET(mLeftJoinProcessEqualGrp(pCtx, probeTs, false)); @@ -999,9 +1026,10 @@ static SSDataBlock* mLeftJoinDo(struct SOperatorInfo* pOperator) { return pCtx->finBlk; } - MJOIN_GET_TB_CUR_TS(pBuildCol, buildTs, pJoin->build); - MJOIN_GET_TB_CUR_TS(pProbeCol, probeTs, pJoin->probe); + MJOIN_GET_TB_COL_TS(pBuildCol, buildTs, pJoin->build); + MJOIN_GET_TB_COL_TS(pProbeCol, probeTs, pJoin->probe); } else if (LEFT_JOIN_NO_EQUAL(asc, probeTs, buildTs)) { + pCtx->probeNEqGrp.blk = pJoin->probe->blk; pCtx->probeNEqGrp.beginIdx = pJoin->probe->blkRowIdx; pCtx->probeNEqGrp.readIdx = pCtx->probeNEqGrp.beginIdx; pCtx->probeNEqGrp.endIdx = pCtx->probeNEqGrp.beginIdx; @@ -1031,6 +1059,20 @@ static SSDataBlock* mLeftJoinDo(struct SOperatorInfo* pOperator) { } } } + + if (!MJOIN_PROBE_TB_ROWS_DONE(pJoin->probe)) { + pCtx->probeNEqGrp.blk = pJoin->probe->blk; + pCtx->probeNEqGrp.beginIdx = pJoin->probe->blkRowIdx; + pCtx->probeNEqGrp.readIdx = pCtx->probeNEqGrp.beginIdx; + pCtx->probeNEqGrp.endIdx = pJoin->probe->blk->info.rows - 1; + + pJoin->probe->blkRowIdx = pJoin->probe->blk->info.rows; + + MJ_ERR_JRET(mLeftJoinNonEqCart(pCtx)); + if (pCtx->finBlk->info.rows >= pCtx->blkThreshold) { + return pCtx->finBlk; + } + } } while (true); _return: @@ -1147,9 +1189,7 @@ SOperatorInfo* createMergeJoinOperatorInfo(SOperatorInfo** pDownstream, int32_t mJoinInitTableInfo(pInfo, pJoinNode, pDownstream, 0, &pJoinNode->inputStat[0]); mJoinInitTableInfo(pInfo, pJoinNode, pDownstream, 1, &pJoinNode->inputStat[1]); - - MJ_ERR_JRET(mJoinInitCtx(pInfo, pJoinNode)); - + if (pJoinNode->pFullOnCond != NULL) { MJ_ERR_JRET(filterInitFromNode(pJoinNode->pFullOnCond, &pInfo->pFPreFilter, 0)); } @@ -1162,6 +1202,8 @@ SOperatorInfo* createMergeJoinOperatorInfo(SOperatorInfo** pDownstream, int32_t MJ_ERR_JRET(filterInitFromNode(pJoinNode->node.pConditions, &pInfo->pFinFilter, 0)); } + MJ_ERR_JRET(mJoinInitCtx(pInfo, pJoinNode)); + if (pJoinNode->node.inputTsOrder == ORDER_ASC) { pInfo->inputTsOrder = TSDB_ORDER_ASC; } else if (pJoinNode->node.inputTsOrder == ORDER_DESC) { diff --git a/source/libs/planner/src/planOptimizer.c b/source/libs/planner/src/planOptimizer.c index e304bb232e..f2599e364c 100644 --- a/source/libs/planner/src/planOptimizer.c +++ b/source/libs/planner/src/planOptimizer.c @@ -555,7 +555,7 @@ static EDealRes pdcJoinIsCrossTableCond(SNode* pNode, void* pContext) { } static ECondAction pdcJoinGetCondAction(SJoinLogicNode* pJoin, SSHashObj* pLeftTbls, SSHashObj* pRightTbls, - SNode* pNode) { + SNode* pNode, bool whereCond) { EJoinType t = pJoin->joinType; EJoinSubType s = pJoin->subType; SCpdIsMultiTableCondCxt cxt = { @@ -564,19 +564,19 @@ static ECondAction pdcJoinGetCondAction(SJoinLogicNode* pJoin, SSHashObj* pLeftT if (cxt.havaLeftCol) { if (cxt.haveRightCol) { - if (gJoinOpt[t][s].pushDownFlag & PUSH_DOWN_ON_COND) { + if ((!whereCond) || (gJoinOpt[t][s].pushDownFlag & PUSH_DOWN_ON_COND)) { return COND_ACTION_PUSH_JOIN; } return COND_ACTION_STAY; } - if (gJoinOpt[t][s].pushDownFlag & PUSH_DOWN_LEFT_FLT) { + if ((!whereCond) || (gJoinOpt[t][s].pushDownFlag & PUSH_DOWN_LEFT_FLT)) { return COND_ACTION_PUSH_LEFT_CHILD; } return COND_ACTION_STAY; } if (cxt.haveRightCol) { - if (gJoinOpt[t][s].pushDownFlag & PUSH_DOWN_RIGHT_FLT) { + if ((!whereCond) || (gJoinOpt[t][s].pushDownFlag & PUSH_DOWN_RIGHT_FLT)) { return COND_ACTION_PUSH_RIGHT_CHILD; } return COND_ACTION_STAY; @@ -586,7 +586,7 @@ static ECondAction pdcJoinGetCondAction(SJoinLogicNode* pJoin, SSHashObj* pLeftT } static int32_t pdcJoinSplitLogicCond(SJoinLogicNode* pJoin, SNode** pSrcCond, SNode** pOnCond, SNode** pLeftChildCond, - SNode** pRightChildCond) { + SNode** pRightChildCond, bool whereCond) { SLogicConditionNode* pLogicCond = (SLogicConditionNode*)*pSrcCond; if (LOGIC_COND_TYPE_AND != pLogicCond->condType) { return TSDB_CODE_PLAN_NOT_SUPPORT_JOIN_COND; @@ -604,7 +604,7 @@ static int32_t pdcJoinSplitLogicCond(SJoinLogicNode* pJoin, SNode** pSrcCond, SN SNodeList* pRemainConds = NULL; SNode* pCond = NULL; FOREACH(pCond, pLogicCond->pParameterList) { - ECondAction condAction = pdcJoinGetCondAction(pJoin, pLeftTables, pRightTables, pCond); + ECondAction condAction = pdcJoinGetCondAction(pJoin, pLeftTables, pRightTables, pCond, whereCond); if (COND_ACTION_PUSH_JOIN == condAction && NULL != pOnCond) { code = nodesListMakeAppend(&pOnConds, nodesCloneNode(pCond)); } else if (COND_ACTION_PUSH_LEFT_CHILD == condAction) { @@ -662,13 +662,13 @@ static int32_t pdcJoinSplitLogicCond(SJoinLogicNode* pJoin, SNode** pSrcCond, SN } static int32_t pdcJoinSplitOpCond(SJoinLogicNode* pJoin, SNode** pSrcCond, SNode** pOnCond, SNode** pLeftChildCond, - SNode** pRightChildCond) { + SNode** pRightChildCond, bool whereCond) { SSHashObj* pLeftTables = NULL; SSHashObj* pRightTables = NULL; collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 0), &pLeftTables); collectTableAliasFromNodes(nodesListGetNode(pJoin->node.pChildren, 1), &pRightTables); - ECondAction condAction = pdcJoinGetCondAction(pJoin, pLeftTables, pRightTables, *pSrcCond); + ECondAction condAction = pdcJoinGetCondAction(pJoin, pLeftTables, pRightTables, *pSrcCond, whereCond); tSimpleHashCleanup(pLeftTables); tSimpleHashCleanup(pRightTables); @@ -689,11 +689,11 @@ static int32_t pdcJoinSplitOpCond(SJoinLogicNode* pJoin, SNode** pSrcCond, SNode } static int32_t pdcJoinSplitCond(SJoinLogicNode* pJoin, SNode** pSrcCond, SNode** pOnCond, SNode** pLeftChildCond, - SNode** pRightChildCond) { + SNode** pRightChildCond, bool whereCond) { if (QUERY_NODE_LOGIC_CONDITION == nodeType(*pSrcCond)) { - return pdcJoinSplitLogicCond(pJoin, pSrcCond, pOnCond, pLeftChildCond, pRightChildCond); + return pdcJoinSplitLogicCond(pJoin, pSrcCond, pOnCond, pLeftChildCond, pRightChildCond, whereCond); } else { - return pdcJoinSplitOpCond(pJoin, pSrcCond, pOnCond, pLeftChildCond, pRightChildCond); + return pdcJoinSplitOpCond(pJoin, pSrcCond, pOnCond, pLeftChildCond, pRightChildCond, whereCond); } } @@ -1132,7 +1132,7 @@ static int32_t pdcDealJoin(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) { SNode* pRightChildCond = NULL; int32_t code = pdcJoinCheckAllCond(pCxt, pJoin); if (TSDB_CODE_SUCCESS == code && NULL != pJoin->node.pConditions && 0 != gJoinOpt[t][s].pushDownFlag) { - code = pdcJoinSplitCond(pJoin, &pJoin->node.pConditions, &pOnCond, &pLeftChildCond, &pRightChildCond); + code = pdcJoinSplitCond(pJoin, &pJoin->node.pConditions, &pOnCond, &pLeftChildCond, &pRightChildCond, true); if (TSDB_CODE_SUCCESS == code && NULL != pOnCond) { code = pdcJoinPushDownOnCond(pCxt, pJoin, &pOnCond); } @@ -1145,7 +1145,7 @@ static int32_t pdcDealJoin(SOptimizeContext* pCxt, SJoinLogicNode* pJoin) { } if (TSDB_CODE_SUCCESS == code) { - code = pdcJoinSplitCond(pJoin, &pJoin->pFullOnCond, NULL, &pLeftChildCond, &pRightChildCond); + code = pdcJoinSplitCond(pJoin, &pJoin->pFullOnCond, NULL, &pLeftChildCond, &pRightChildCond, false); if (TSDB_CODE_SUCCESS == code && NULL != pLeftChildCond) { code = pdcPushDownCondToChild(pCxt, (SLogicNode*)nodesListGetNode(pJoin->node.pChildren, 0), &pLeftChildCond); } diff --git a/tests/script/tsim/join/join.sim b/tests/script/tsim/join/join.sim new file mode 100644 index 0000000000..bb4b9dbee0 --- /dev/null +++ b/tests/script/tsim/join/join.sim @@ -0,0 +1,69 @@ +system sh/stop_dnodes.sh +system sh/deploy.sh -n dnode1 -i 1 +system sh/exec.sh -n dnode1 -s start +sql connect +sql drop database if exists test0 +sql create database test0 vgroups 3; +sql use test0; +create stable sta (ts timestamp, col1 int) tags(t1 int); +create table tba1 using sta tags(1); +create table tba2 using sta tags(2); + +insert into tba1 values ('2023-11-17 16:29:00', 1); +insert into tba1 values ('2023-11-17 16:29:02', 3); +insert into tba1 values ('2023-11-17 16:29:03', 4); +insert into tba1 values ('2023-11-17 16:29:04', 5); + +insert into tba2 values ('2023-11-17 16:29:00', 2); +insert into tba2 values ('2023-11-17 16:29:01', 3); +insert into tba2 values ('2023-11-17 16:29:03', 5); +insert into tba2 values ('2023-11-17 16:29:05', 7); + +sql drop database if exists testa +sql create database testa vgroups 3; +sql use testa; + +sql create table sta1(ts timestamp, f int, g int) tags (t int); +sql insert into cta11 using sta1 tags(1) values('2023-10-16 09:10:11', 100111, 1001110); +sql insert into cta12 using sta1 tags(2) values('2023-10-16 09:10:12', 100112, 1001120); +sql insert into cta13 using sta1 tags(3) values('2023-10-16 09:10:13', 100113, 1001130); +sql insert into cta14 using sta1 tags(4) values('2023-10-16 09:10:14', 100114, 1001140); + +sql create table st2(ts timestamp, f int, g int) tags (t int); +sql insert into cta21 using st2 tags(1) values('2023-10-16 09:10:11', 100221, 1002210); +sql insert into cta22 using st2 tags(2) values('2023-10-16 09:10:12', 100222, 1002220); +sql insert into cta23 using st2 tags(3) values('2023-10-16 09:10:13', 100223, 1002230); +sql insert into cta24 using st2 tags(4) values('2023-10-16 09:10:14', 100224, 1002240); + +sql create table stt(ts timestamp, f int, g int) tags (t int); +sql create table tt using stt tags(99); + +sql create table stv(ts timestamp, h int) tags (t1 int); +sql insert into ctv1 using stv tags(1) values('2023-10-16 10:10:10', 1); + +sql drop database if exists testb +sql create database testb vgroups 1; +sql use testb; + +sql create table stb1(ts timestamp, f int,g int) tags (t int); +sql insert into ctb11 using stb1 tags(1) values('2023-10-16 09:10:11', 110111, 1101110); +sql insert into ctb12 using stb1 tags(2) values('2023-10-16 09:10:12', 110112, 1101120); +sql insert into ctb13 using stb1 tags(3) values('2023-10-16 09:10:13', 110113, 1101130); +sql insert into ctb14 using stb1 tags(4) values('2023-10-16 09:10:14', 110114, 1101140); + +sql create table st2(ts timestamp, f int, g int) tags (t int); +sql insert into ctb21 using st2 tags(1) values('2023-10-16 09:10:11', 110221, 1102210); +sql insert into ctb22 using st2 tags(2) values('2023-10-16 09:10:12', 110222, 1102220); +sql insert into ctb23 using st2 tags(3) values('2023-10-16 09:10:13', 110223, 1102230); +sql insert into ctb24 using st2 tags(4) values('2023-10-16 09:10:14', 110224, 1102240); + +run tsim/join/left_join.sim + +print ================== restart server to commit data into disk +system sh/exec.sh -n dnode1 -s stop -x SIGINT +system sh/exec.sh -n dnode1 -s start +print ================== server restart completed + +run tsim/join/left_join.sim + +system sh/exec.sh -n dnode1 -s stop -x SIGINT diff --git a/tests/script/tsim/join/left_join.sim b/tests/script/tsim/join/left_join.sim new file mode 100644 index 0000000000..214b5ec9f6 --- /dev/null +++ b/tests/script/tsim/join/left_join.sim @@ -0,0 +1,96 @@ +sql connect +sql use test0; + +sql select a.col1, b.col1 from sta a left join sta b on a.ts = b.ts and a.ts < '2023-11-17 16:29:02' and b.ts < '2023-11-17 16:29:01' order by a.col1, b.col1; +if $rows != 5 then + return -1 +endi +if $data00 != 1 then + return -1 +endi +if $data01 != 1 then + return -1 +endi +if $data10 != 1 then + return -1 +endi +if $data11 != 2 then + return -1 +endi +if $data20 != 2 then + return -1 +endi +if $data21 != 1 then + return -1 +endi +if $data30 != 2 then + return -1 +endi +if $data31 != 2 then + return -1 +endi +if $data40 != 3 then + return -1 +endi +if $data41 != NULL then + return -1 +endi + +sql select a.col1, b.col1 from tba1 a left join tba2 b on a.ts = b.ts order by a.col1, b.col1; +if $rows != 4 then + return -1 +endi +if $data00 != 1 then + return -1 +endi +if $data01 != 2 then + return -1 +endi +if $data10 != 3 then + return -1 +endi +if $data11 != NULL then + return -1 +endi +if $data20 != 4 then + return -1 +endi +if $data21 != 5 then + return -1 +endi +if $data30 != 5 then + return -1 +endi +if $data31 != NULL then + return -1 +endi + +sql select a.col1, b.col1 from tba2 a left join tba1 b on a.ts = b.ts order by a.col1, b.col1; +if $rows != 4 then + return -1 +endi +if $data00 != 2 then + return -1 +endi +if $data01 != 1 then + return -1 +endi +if $data10 != 3 then + return -1 +endi +if $data11 != NULL then + return -1 +endi +if $data20 != 5 then + return -1 +endi +if $data21 != 4 then + return -1 +endi +if $data30 != 7 then + return -1 +endi +if $data31 != NULL then + return -1 +endi +