未验证 提交 9a9c179d 编写于 作者: S shenglian-zhou 提交者: GitHub

Merge pull request #15799 from taosdata/szhou/fix/nullgroup

fix: all null value group with all null out
...@@ -202,6 +202,7 @@ bool fmIsForbidStreamFunc(int32_t funcId); ...@@ -202,6 +202,7 @@ bool fmIsForbidStreamFunc(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); bool fmIsLastRowFunc(int32_t funcId);
bool fmIsReturnNotNullFunc(int32_t funcId);
bool fmIsSelectValueFunc(int32_t funcId); bool fmIsSelectValueFunc(int32_t funcId);
bool fmIsSystemInfoFunc(int32_t funcId); bool fmIsSystemInfoFunc(int32_t funcId);
bool fmIsImplicitTsFunc(int32_t funcId); bool fmIsImplicitTsFunc(int32_t funcId);
......
...@@ -1437,7 +1437,8 @@ static void setExecutionContext(SOperatorInfo* pOperator, int32_t numOfOutput, u ...@@ -1437,7 +1437,8 @@ static void setExecutionContext(SOperatorInfo* pOperator, int32_t numOfOutput, u
pAggInfo->groupId = groupId; pAggInfo->groupId = groupId;
} }
static void doUpdateNumOfRows(SResultRow* pRow, int32_t numOfExprs, const int32_t* rowCellOffset) { static void doUpdateNumOfRows(SqlFunctionCtx* pCtx, SResultRow* pRow, int32_t numOfExprs, const int32_t* rowCellOffset) {
bool returnNotNull = false;
for (int32_t j = 0; j < numOfExprs; ++j) { for (int32_t j = 0; j < numOfExprs; ++j) {
struct SResultRowEntryInfo* pResInfo = getResultEntryInfo(pRow, j, rowCellOffset); struct SResultRowEntryInfo* pResInfo = getResultEntryInfo(pRow, j, rowCellOffset);
if (!isRowEntryInitialized(pResInfo)) { if (!isRowEntryInitialized(pResInfo)) {
...@@ -1447,6 +1448,15 @@ static void doUpdateNumOfRows(SResultRow* pRow, int32_t numOfExprs, const int32_ ...@@ -1447,6 +1448,15 @@ static void doUpdateNumOfRows(SResultRow* pRow, int32_t numOfExprs, const int32_
if (pRow->numOfRows < pResInfo->numOfRes) { if (pRow->numOfRows < pResInfo->numOfRes) {
pRow->numOfRows = pResInfo->numOfRes; pRow->numOfRows = pResInfo->numOfRes;
} }
if (fmIsReturnNotNullFunc(pCtx[j].functionId)) {
returnNotNull = true;
}
}
// if all expr skips all blocks, e.g. all null inputs for max function, output one row in final result.
// except for first/last, which require not null output, output no rows
if (pRow->numOfRows == 0 && !returnNotNull) {
pRow->numOfRows = 1;
} }
} }
...@@ -1458,7 +1468,7 @@ int32_t finalizeResultRowIntoResultDataBlock(SDiskbasedBuf* pBuf, SResultRowPosi ...@@ -1458,7 +1468,7 @@ int32_t finalizeResultRowIntoResultDataBlock(SDiskbasedBuf* pBuf, SResultRowPosi
SFilePage* page = getBufPage(pBuf, resultRowPosition->pageId); SFilePage* page = getBufPage(pBuf, resultRowPosition->pageId);
SResultRow* pRow = (SResultRow*)((char*)page + resultRowPosition->offset); SResultRow* pRow = (SResultRow*)((char*)page + resultRowPosition->offset);
doUpdateNumOfRows(pRow, numOfExprs, rowCellOffset); doUpdateNumOfRows(pCtx, pRow, numOfExprs, rowCellOffset);
if (pRow->numOfRows == 0) { if (pRow->numOfRows == 0) {
releaseBufPage(pBuf, page); releaseBufPage(pBuf, page);
return 0; return 0;
...@@ -1514,7 +1524,7 @@ int32_t doCopyToSDataBlock(SExecTaskInfo* pTaskInfo, SSDataBlock* pBlock, SExprI ...@@ -1514,7 +1524,7 @@ int32_t doCopyToSDataBlock(SExecTaskInfo* pTaskInfo, SSDataBlock* pBlock, SExprI
SResultRow* pRow = (SResultRow*)((char*)page + pPos->pos.offset); SResultRow* pRow = (SResultRow*)((char*)page + pPos->pos.offset);
doUpdateNumOfRows(pRow, numOfExprs, rowCellOffset); doUpdateNumOfRows(pCtx, pRow, numOfExprs, rowCellOffset);
if (pRow->numOfRows == 0) { if (pRow->numOfRows == 0) {
pGroupResInfo->index += 1; pGroupResInfo->index += 1;
releaseBufPage(pBuf, page); releaseBufPage(pBuf, page);
......
...@@ -64,6 +64,9 @@ typedef struct SMinmaxResInfo { ...@@ -64,6 +64,9 @@ typedef struct SMinmaxResInfo {
bool assign; // assign the first value or not bool assign; // assign the first value or not
int64_t v; int64_t v;
STuplePos tuplePos; STuplePos tuplePos;
STuplePos nullTuplePos;
bool nullTupleSaved;
} SMinmaxResInfo; } SMinmaxResInfo;
typedef struct STopBotResItem { typedef struct STopBotResItem {
...@@ -75,6 +78,10 @@ typedef struct STopBotResItem { ...@@ -75,6 +78,10 @@ typedef struct STopBotResItem {
typedef struct STopBotRes { typedef struct STopBotRes {
int32_t maxSize; int32_t maxSize;
int16_t type; int16_t type;
STuplePos nullTuplePos;
bool nullTupleSaved;
STopBotResItem* pItems; STopBotResItem* pItems;
} STopBotRes; } STopBotRes;
...@@ -221,6 +228,10 @@ typedef struct SSampleInfo { ...@@ -221,6 +228,10 @@ typedef struct SSampleInfo {
int32_t numSampled; int32_t numSampled;
uint8_t colType; uint8_t colType;
int16_t colBytes; int16_t colBytes;
STuplePos nullTuplePos;
bool nullTupleSaved;
char* data; char* data;
STuplePos* tuplePos; STuplePos* tuplePos;
} SSampleInfo; } SSampleInfo;
...@@ -1134,6 +1145,9 @@ bool minmaxFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) ...@@ -1134,6 +1145,9 @@ bool minmaxFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo)
SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo); SMinmaxResInfo* buf = GET_ROWCELL_INTERBUF(pResultInfo);
buf->assign = false; buf->assign = false;
buf->tuplePos.pageId = -1; buf->tuplePos.pageId = -1;
buf->nullTupleSaved = false;
buf->nullTuplePos.pageId = -1;
return true; return true;
} }
...@@ -1575,6 +1589,10 @@ int32_t doMinMaxHelper(SqlFunctionCtx* pCtx, int32_t isMinFunc) { ...@@ -1575,6 +1589,10 @@ int32_t doMinMaxHelper(SqlFunctionCtx* pCtx, int32_t isMinFunc) {
} }
_min_max_over: _min_max_over:
if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pBuf->nullTupleSaved ) {
doSaveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pBuf->nullTuplePos);
pBuf->nullTupleSaved = true;
}
return numOfElems; return numOfElems;
} }
...@@ -1615,7 +1633,7 @@ int32_t minmaxFunctionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { ...@@ -1615,7 +1633,7 @@ int32_t minmaxFunctionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
if (pEntryInfo->numOfRes > 0) { if (pEntryInfo->numOfRes > 0) {
setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow); setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
} else { } else {
setNullSelectivityValue(pCtx, pBlock, currentRow); setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
} }
return pEntryInfo->numOfRes; return pEntryInfo->numOfRes;
...@@ -3366,6 +3384,8 @@ bool topBotFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) { ...@@ -3366,6 +3384,8 @@ bool topBotFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResInfo) {
pRes->maxSize = pCtx->param[1].param.i; pRes->maxSize = pCtx->param[1].param.i;
pRes->nullTupleSaved = false;
pRes->nullTuplePos.pageId = -1;
return true; return true;
} }
...@@ -3403,6 +3423,10 @@ int32_t topFunction(SqlFunctionCtx* pCtx) { ...@@ -3403,6 +3423,10 @@ int32_t topFunction(SqlFunctionCtx* pCtx) {
doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, true); doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, true);
} }
if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
doSaveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
pRes->nullTupleSaved = true;
}
return TSDB_CODE_SUCCESS; return TSDB_CODE_SUCCESS;
} }
...@@ -3427,6 +3451,11 @@ int32_t bottomFunction(SqlFunctionCtx* pCtx) { ...@@ -3427,6 +3451,11 @@ int32_t bottomFunction(SqlFunctionCtx* pCtx) {
doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, false); doAddIntoResult(pCtx, data, i, pCtx->pSrcBlock, pRes->type, pInput->uid, pResInfo, false);
} }
if (numOfElems == 0 && pCtx->subsidiaries.num > 0 && !pRes->nullTupleSaved) {
doSaveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pRes->nullTuplePos);
pRes->nullTupleSaved = true;
}
return TSDB_CODE_SUCCESS; return TSDB_CODE_SUCCESS;
} }
...@@ -3625,6 +3654,11 @@ int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { ...@@ -3625,6 +3654,11 @@ int32_t topBotFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
// todo assign the tag value and the corresponding row data // todo assign the tag value and the corresponding row data
int32_t currentRow = pBlock->info.rows; int32_t currentRow = pBlock->info.rows;
if (pEntryInfo->numOfRes <= 0) {
colDataAppendNULL(pCol, currentRow);
setSelectivityValue(pCtx, pBlock, &pRes->nullTuplePos, currentRow);
return pEntryInfo->numOfRes;
}
for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) { for (int32_t i = 0; i < pEntryInfo->numOfRes; ++i) {
STopBotResItem* pItem = &pRes->pItems[i]; STopBotResItem* pItem = &pRes->pItems[i];
if (type == TSDB_DATA_TYPE_FLOAT) { if (type == TSDB_DATA_TYPE_FLOAT) {
...@@ -4897,7 +4931,8 @@ bool sampleFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo) ...@@ -4897,7 +4931,8 @@ bool sampleFunctionSetup(SqlFunctionCtx* pCtx, SResultRowEntryInfo* pResultInfo)
pInfo->numSampled = 0; pInfo->numSampled = 0;
pInfo->colType = pCtx->resDataInfo.type; pInfo->colType = pCtx->resDataInfo.type;
pInfo->colBytes = pCtx->resDataInfo.bytes; pInfo->colBytes = pCtx->resDataInfo.bytes;
pInfo->nullTuplePos.pageId = -1;
pInfo->nullTupleSaved = false;
pInfo->data = (char*)pInfo + sizeof(SSampleInfo); pInfo->data = (char*)pInfo + sizeof(SSampleInfo);
pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes); pInfo->tuplePos = (STuplePos*)((char*)pInfo + sizeof(SSampleInfo) + pInfo->samples * pInfo->colBytes);
...@@ -4943,6 +4978,11 @@ int32_t sampleFunction(SqlFunctionCtx* pCtx) { ...@@ -4943,6 +4978,11 @@ int32_t sampleFunction(SqlFunctionCtx* pCtx) {
doReservoirSample(pCtx, pInfo, data, i); doReservoirSample(pCtx, pInfo, data, i);
} }
if (pInfo->numSampled == 0 && pCtx->subsidiaries.num > 0 && !pInfo->nullTupleSaved) {
doSaveTupleData(pCtx, pInput->startRowIndex, pCtx->pSrcBlock, &pInfo->nullTuplePos);
pInfo->nullTupleSaved = true;
}
SET_VAL(pResInfo, pInfo->numSampled, pInfo->numSampled); SET_VAL(pResInfo, pInfo->numSampled, pInfo->numSampled);
return TSDB_CODE_SUCCESS; return TSDB_CODE_SUCCESS;
} }
...@@ -4957,6 +4997,11 @@ int32_t sampleFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) { ...@@ -4957,6 +4997,11 @@ int32_t sampleFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId); SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
int32_t currentRow = pBlock->info.rows; int32_t currentRow = pBlock->info.rows;
if (pInfo->numSampled == 0) {
colDataAppendNULL(pCol, currentRow);
setSelectivityValue(pCtx, pBlock, &pInfo->nullTuplePos, currentRow);
return pInfo->numSampled;
}
for (int32_t i = 0; i < pInfo->numSampled; ++i) { for (int32_t i = 0; i < pInfo->numSampled; ++i) {
colDataAppend(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false); colDataAppend(pCol, currentRow + i, pInfo->data + i * pInfo->colBytes, false);
setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i); setSelectivityValue(pCtx, pBlock, &pInfo->tuplePos[i], currentRow + i);
......
...@@ -221,6 +221,18 @@ bool fmIsLastRowFunc(int32_t funcId) { ...@@ -221,6 +221,18 @@ bool fmIsLastRowFunc(int32_t funcId) {
return FUNCTION_TYPE_LAST_ROW == funcMgtBuiltins[funcId].type; return FUNCTION_TYPE_LAST_ROW == funcMgtBuiltins[funcId].type;
} }
bool fmIsReturnNotNullFunc(int32_t funcId) {
if (funcId < 0 || funcId >= funcMgtBuiltinsNum) {
return false;
}
return FUNCTION_TYPE_LAST == funcMgtBuiltins[funcId].type ||
FUNCTION_TYPE_LAST_PARTIAL == funcMgtBuiltins[funcId].type ||
FUNCTION_TYPE_LAST_MERGE == funcMgtBuiltins[funcId].type ||
FUNCTION_TYPE_FIRST == funcMgtBuiltins[funcId].type ||
FUNCTION_TYPE_FIRST_PARTIAL == funcMgtBuiltins[funcId].type ||
FUNCTION_TYPE_FIRST_MERGE == funcMgtBuiltins[funcId].type;
}
bool fmIsSelectValueFunc(int32_t funcId) { bool fmIsSelectValueFunc(int32_t funcId) {
if (funcId < 0 || funcId >= funcMgtBuiltinsNum) { if (funcId < 0 || funcId >= funcMgtBuiltinsNum) {
return false; return false;
......
...@@ -327,8 +327,8 @@ endi ...@@ -327,8 +327,8 @@ endi
print =================>td-2610 print =================>td-2610
sql select stddev(k) from tm2 where ts='2020-12-29 18:46:19.109' sql select stddev(k) from tm2 where ts='2020-12-29 18:46:19.109'
if $rows != 0 then if $rows != 1 then
print expect 0, actual:$rows print expect 1, actual:$rows
return -1 return -1
endi endi
sql select twa(k) from tm2 where ts='2020-12-29 18:46:19.109' sql select twa(k) from tm2 where ts='2020-12-29 18:46:19.109'
...@@ -406,7 +406,7 @@ if $data00 != 1.378704626 then ...@@ -406,7 +406,7 @@ if $data00 != 1.378704626 then
endi endi
sql select stddev(c) from m1 sql select stddev(c) from m1
if $rows != 0 then if $rows != 1 then
return -1 return -1
endi endi
......
...@@ -295,7 +295,7 @@ class TDTestCase: ...@@ -295,7 +295,7 @@ class TDTestCase:
tdSql.checkData(0, 0, 4.500000000) tdSql.checkData(0, 0, 4.500000000)
tdSql.query(f" select avg(c1) from {dbname}.stb1 where c1 is null ") tdSql.query(f" select avg(c1) from {dbname}.stb1 where c1 is null ")
tdSql.checkRows(0) tdSql.checkRows(1)
def avg_func_filter(self, dbname="db"): def avg_func_filter(self, dbname="db"):
......
...@@ -86,7 +86,7 @@ class TDTestCase: ...@@ -86,7 +86,7 @@ class TDTestCase:
def distribute_agg_query(self, dbname="testdb"): def distribute_agg_query(self, dbname="testdb"):
# basic filter # basic filter
tdSql.query(f"select apercentile(c1 , 20) from {dbname}.stb1 where c1 is null") tdSql.query(f"select apercentile(c1 , 20) from {dbname}.stb1 where c1 is null")
tdSql.checkRows(0) tdSql.checkRows(1)
tdSql.query(f"select apercentile(c1 , 20) from {dbname}.stb1 where t1=1") tdSql.query(f"select apercentile(c1 , 20) from {dbname}.stb1 where t1=1")
tdSql.checkData(0,0,2.800000000) tdSql.checkData(0,0,2.800000000)
......
...@@ -168,7 +168,7 @@ class TDTestCase: ...@@ -168,7 +168,7 @@ class TDTestCase:
def distribute_agg_query(self, dbname="testdb"): def distribute_agg_query(self, dbname="testdb"):
# basic filter # basic filter
tdSql.query(f"select max(c1) from {dbname}.stb1 where c1 is null") tdSql.query(f"select max(c1) from {dbname}.stb1 where c1 is null")
tdSql.checkRows(0) tdSql.checkRows(1)
tdSql.query(f"select max(c1) from {dbname}.stb1 where t1=1") tdSql.query(f"select max(c1) from {dbname}.stb1 where t1=1")
tdSql.checkData(0,0,10) tdSql.checkData(0,0,10)
......
...@@ -167,7 +167,7 @@ class TDTestCase: ...@@ -167,7 +167,7 @@ class TDTestCase:
def distribute_agg_query(self, dbname="testdb"): def distribute_agg_query(self, dbname="testdb"):
# basic filter # basic filter
tdSql.query(f"select min(c1) from {dbname}.stb1 where c1 is null") tdSql.query(f"select min(c1) from {dbname}.stb1 where c1 is null")
tdSql.checkRows(0) tdSql.checkRows(1)
tdSql.query(f"select min(c1) from {dbname}.stb1 where t1=1") tdSql.query(f"select min(c1) from {dbname}.stb1 where t1=1")
tdSql.checkData(0,0,2) tdSql.checkData(0,0,2)
......
...@@ -195,7 +195,7 @@ class TDTestCase: ...@@ -195,7 +195,7 @@ class TDTestCase:
def distribute_agg_query(self): def distribute_agg_query(self):
# basic filter # basic filter
tdSql.query("select spread(c1) from stb1 where c1 is null") tdSql.query("select spread(c1) from stb1 where c1 is null")
tdSql.checkRows(0) tdSql.checkRows(1)
tdSql.query("select spread(c1) from stb1 where t1=1") tdSql.query("select spread(c1) from stb1 where t1=1")
tdSql.checkData(0,0,8.000000000) tdSql.checkData(0,0,8.000000000)
......
...@@ -743,7 +743,7 @@ class TDTestCase: ...@@ -743,7 +743,7 @@ class TDTestCase:
# filter data # filter data
tdSql.query(" select sample(c1, 20 ) from t1 where c1 is null ") tdSql.query(" select sample(c1, 20 ) from t1 where c1 is null ")
tdSql.checkRows(0) tdSql.checkRows(1)
tdSql.query(" select sample(c1, 20 ) from t1 where c1 =6 ") tdSql.query(" select sample(c1, 20 ) from t1 where c1 =6 ")
tdSql.checkRows(1) tdSql.checkRows(1)
...@@ -891,4 +891,4 @@ class TDTestCase: ...@@ -891,4 +891,4 @@ class TDTestCase:
tdLog.success("%s successfully executed" % __file__) tdLog.success("%s successfully executed" % __file__)
tdCases.addWindows(__file__, TDTestCase()) tdCases.addWindows(__file__, TDTestCase())
tdCases.addLinux(__file__, TDTestCase()) tdCases.addLinux(__file__, TDTestCase())
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册