Merge pull request #12651 from taosdata/feature/3.0_glzhao
enh(query): support sum(NULL), max(NULL), min(NULL), count(NULL)
This commit is contained in:
commit
fba964778b
|
@ -179,6 +179,8 @@ typedef struct {
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
//TODO: use varchar(0) to represent NULL type
|
||||
#define IS_NULL_TYPE(_t) ((_t) == TSDB_DATA_TYPE_NULL)
|
||||
#define IS_SIGNED_NUMERIC_TYPE(_t) ((_t) >= TSDB_DATA_TYPE_TINYINT && (_t) <= TSDB_DATA_TYPE_BIGINT)
|
||||
#define IS_UNSIGNED_NUMERIC_TYPE(_t) ((_t) >= TSDB_DATA_TYPE_UTINYINT && (_t) <= TSDB_DATA_TYPE_UBIGINT)
|
||||
#define IS_FLOAT_TYPE(_t) ((_t) == TSDB_DATA_TYPE_FLOAT || (_t) == TSDB_DATA_TYPE_DOUBLE)
|
||||
|
|
|
@ -74,6 +74,7 @@ int32_t diffFunction(SqlFunctionCtx *pCtx);
|
|||
bool getFirstLastFuncEnv(struct SFunctionNode* pFunc, SFuncExecEnv* pEnv);
|
||||
int32_t firstFunction(SqlFunctionCtx *pCtx);
|
||||
int32_t lastFunction(SqlFunctionCtx *pCtx);
|
||||
int32_t lastFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock);
|
||||
|
||||
bool getTopBotFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv);
|
||||
int32_t topFunction(SqlFunctionCtx *pCtx);
|
||||
|
|
|
@ -47,8 +47,10 @@ static int32_t translateInOutNum(SFunctionNode* pFunc, char* pErrBuf, int32_t le
|
|||
}
|
||||
|
||||
uint8_t paraType = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 0))->resType.type;
|
||||
if (!IS_NUMERIC_TYPE(paraType)) {
|
||||
if (!IS_NUMERIC_TYPE(paraType) && !IS_NULL_TYPE(paraType)) {
|
||||
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
|
||||
} else if (IS_NULL_TYPE(paraType)) {
|
||||
paraType = TSDB_DATA_TYPE_BIGINT;
|
||||
}
|
||||
|
||||
pFunc->node.resType = (SDataType){.bytes = tDataTypes[paraType].bytes, .type = paraType};
|
||||
|
@ -62,7 +64,7 @@ static int32_t translateInNumOutDou(SFunctionNode* pFunc, char* pErrBuf, int32_t
|
|||
}
|
||||
|
||||
uint8_t paraType = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 0))->resType.type;
|
||||
if (!IS_NUMERIC_TYPE(paraType)) {
|
||||
if (!IS_NUMERIC_TYPE(paraType) && !IS_NULL_TYPE(paraType)) {
|
||||
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
|
||||
}
|
||||
|
||||
|
@ -115,18 +117,19 @@ static int32_t translateSum(SFunctionNode* pFunc, char* pErrBuf, int32_t len) {
|
|||
}
|
||||
|
||||
uint8_t paraType = ((SExprNode*)nodesListGetNode(pFunc->pParameterList, 0))->resType.type;
|
||||
if (!IS_NUMERIC_TYPE(paraType)) {
|
||||
if (!IS_NUMERIC_TYPE(paraType) && !IS_NULL_TYPE(paraType)) {
|
||||
return invaildFuncParaTypeErrMsg(pErrBuf, len, pFunc->functionName);
|
||||
}
|
||||
|
||||
uint8_t resType = 0;
|
||||
if (IS_SIGNED_NUMERIC_TYPE(paraType) || paraType == TSDB_DATA_TYPE_BOOL) {
|
||||
if (IS_SIGNED_NUMERIC_TYPE(paraType) || TSDB_DATA_TYPE_BOOL == paraType || IS_NULL_TYPE(paraType)) {
|
||||
resType = TSDB_DATA_TYPE_BIGINT;
|
||||
} else if (IS_UNSIGNED_NUMERIC_TYPE(paraType)) {
|
||||
resType = TSDB_DATA_TYPE_UBIGINT;
|
||||
} else if (IS_FLOAT_TYPE(paraType)) {
|
||||
resType = TSDB_DATA_TYPE_DOUBLE;
|
||||
}
|
||||
|
||||
pFunc->node.resType = (SDataType){.bytes = tDataTypes[resType].bytes, .type = resType};
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
@ -872,7 +875,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
|||
.getEnvFunc = getFirstLastFuncEnv,
|
||||
.initFunc = functionSetup,
|
||||
.processFunc = lastFunction,
|
||||
.finalizeFunc = functionFinalize
|
||||
.finalizeFunc = lastFinalize
|
||||
},
|
||||
{
|
||||
.name = "diff",
|
||||
|
|
|
@ -255,7 +255,7 @@ int32_t functionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
|
|||
SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
|
||||
|
||||
SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
|
||||
pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
|
||||
//pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
|
||||
|
||||
char* in = GET_ROWCELL_INTERBUF(pResInfo);
|
||||
colDataAppend(pCol, pBlock->info.rows, in, pResInfo->isNullRes);
|
||||
|
@ -331,8 +331,18 @@ static FORCE_INLINE int32_t getNumofElem(SqlFunctionCtx* pCtx) {
|
|||
int32_t countFunction(SqlFunctionCtx* pCtx) {
|
||||
int32_t numOfElem = getNumofElem(pCtx);
|
||||
SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
|
||||
char* buf = GET_ROWCELL_INTERBUF(pResInfo);
|
||||
*((int64_t*)buf) += numOfElem;
|
||||
|
||||
SInputColumnInfoData* pInput = &pCtx->input;
|
||||
int32_t type = pInput->pData[0]->info.type;
|
||||
|
||||
char* buf = GET_ROWCELL_INTERBUF(pResInfo);
|
||||
if (IS_NULL_TYPE(type)) {
|
||||
//select count(NULL) returns 0
|
||||
numOfElem = 1;
|
||||
*((int64_t*)buf) = 0;
|
||||
} else {
|
||||
*((int64_t*)buf) += numOfElem;
|
||||
}
|
||||
|
||||
SET_VAL(pResInfo, numOfElem, 1);
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
@ -378,11 +388,17 @@ int32_t sumFunction(SqlFunctionCtx* pCtx) {
|
|||
|
||||
// Only the pre-computing information loaded and actual data does not loaded
|
||||
SInputColumnInfoData* pInput = &pCtx->input;
|
||||
SColumnDataAgg* pAgg = pInput->pColumnDataAgg[0];
|
||||
int32_t type = pInput->pData[0]->info.type;
|
||||
SColumnDataAgg* pAgg = pInput->pColumnDataAgg[0];
|
||||
int32_t type = pInput->pData[0]->info.type;
|
||||
|
||||
SSumRes* pSumRes = GET_ROWCELL_INTERBUF(GET_RES_INFO(pCtx));
|
||||
|
||||
if (IS_NULL_TYPE(type)) {
|
||||
GET_RES_INFO(pCtx)->isNullRes = 1;
|
||||
numOfElem = 1;
|
||||
goto _sum_over;
|
||||
}
|
||||
|
||||
if (pInput->colDataAggIsSet) {
|
||||
numOfElem = pInput->numOfRows - pAgg->numOfNull;
|
||||
ASSERT(numOfElem >= 0);
|
||||
|
@ -427,6 +443,7 @@ int32_t sumFunction(SqlFunctionCtx* pCtx) {
|
|||
}
|
||||
}
|
||||
|
||||
_sum_over:
|
||||
// data in the check operation are all null, not output
|
||||
SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
@ -526,6 +543,12 @@ int32_t avgFunction(SqlFunctionCtx* pCtx) {
|
|||
int32_t start = pInput->startRowIndex;
|
||||
int32_t numOfRows = pInput->numOfRows;
|
||||
|
||||
if (IS_NULL_TYPE(type)) {
|
||||
GET_RES_INFO(pCtx)->isNullRes = 1;
|
||||
numOfElem = 1;
|
||||
goto _avg_over;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case TSDB_DATA_TYPE_TINYINT: {
|
||||
int8_t* plist = (int8_t*)pCol->pData;
|
||||
|
@ -617,6 +640,7 @@ int32_t avgFunction(SqlFunctionCtx* pCtx) {
|
|||
break;
|
||||
}
|
||||
|
||||
_avg_over:
|
||||
// data in the check operation are all null, not output
|
||||
SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
@ -783,6 +807,12 @@ int32_t doMinMaxHelper(SqlFunctionCtx* pCtx, int32_t isMinFunc) {
|
|||
SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
|
||||
SMinmaxResInfo *pBuf = GET_ROWCELL_INTERBUF(pResInfo);
|
||||
|
||||
if (IS_NULL_TYPE(type)) {
|
||||
GET_RES_INFO(pCtx)->isNullRes = 1;
|
||||
numOfElems = 1;
|
||||
goto _min_max_over;
|
||||
}
|
||||
|
||||
// data in current data block are qualified to the query
|
||||
if (pInput->colDataAggIsSet) {
|
||||
numOfElems = pInput->numOfRows - pAgg->numOfNull;
|
||||
|
@ -1183,6 +1213,7 @@ int32_t doMinMaxHelper(SqlFunctionCtx* pCtx, int32_t isMinFunc) {
|
|||
}
|
||||
}
|
||||
|
||||
_min_max_over:
|
||||
return numOfElems;
|
||||
}
|
||||
|
||||
|
@ -1215,9 +1246,9 @@ int32_t minmaxFunctionFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
|
|||
|
||||
if (pCol->info.type == TSDB_DATA_TYPE_FLOAT) {
|
||||
float v = *(double*) &pRes->v;
|
||||
colDataAppend(pCol, currentRow, (const char*)&v, false);
|
||||
colDataAppend(pCol, currentRow, (const char*)&v, pEntryInfo->isNullRes);
|
||||
} else {
|
||||
colDataAppend(pCol, currentRow, (const char*)&pRes->v, false);
|
||||
colDataAppend(pCol, currentRow, (const char*)&pRes->v, pEntryInfo->isNullRes);
|
||||
}
|
||||
|
||||
setSelectivityValue(pCtx, pBlock, &pRes->tuplePos, currentRow);
|
||||
|
@ -1287,6 +1318,12 @@ int32_t stddevFunction(SqlFunctionCtx* pCtx) {
|
|||
int32_t start = pInput->startRowIndex;
|
||||
int32_t numOfRows = pInput->numOfRows;
|
||||
|
||||
if (IS_NULL_TYPE(type)) {
|
||||
GET_RES_INFO(pCtx)->isNullRes = 1;
|
||||
numOfElem = 1;
|
||||
goto _stddev_over;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case TSDB_DATA_TYPE_TINYINT: {
|
||||
int8_t* plist = (int8_t*)pCol->pData;
|
||||
|
@ -1384,6 +1421,7 @@ int32_t stddevFunction(SqlFunctionCtx* pCtx) {
|
|||
break;
|
||||
}
|
||||
|
||||
_stddev_over:
|
||||
// data in the check operation are all null, not output
|
||||
SET_VAL(GET_RES_INFO(pCtx), numOfElem, 1);
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
@ -1943,6 +1981,19 @@ int32_t lastFunction(SqlFunctionCtx* pCtx) {
|
|||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t lastFinalize(SqlFunctionCtx* pCtx, SSDataBlock* pBlock) {
|
||||
int32_t slotId = pCtx->pExpr->base.resSchema.slotId;
|
||||
SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, slotId);
|
||||
|
||||
SResultRowEntryInfo* pResInfo = GET_RES_INFO(pCtx);
|
||||
pResInfo->isNullRes = (pResInfo->numOfRes == 0) ? 1 : 0;
|
||||
|
||||
char* in = GET_ROWCELL_INTERBUF(pResInfo);
|
||||
colDataAppend(pCol, pBlock->info.rows, in, pResInfo->isNullRes);
|
||||
|
||||
return pResInfo->numOfRes;
|
||||
}
|
||||
|
||||
bool getDiffFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) {
|
||||
pEnv->calcMemSize = sizeof(SDiffInfo);
|
||||
return true;
|
||||
|
|
Loading…
Reference in New Issue