diff --git a/include/libs/nodes/querynodes.h b/include/libs/nodes/querynodes.h index dfb92861d6..34b42fd9e1 100644 --- a/include/libs/nodes/querynodes.h +++ b/include/libs/nodes/querynodes.h @@ -415,7 +415,7 @@ typedef struct SSelectStmt { int32_t returnRows; // EFuncReturnRows ETimeLineMode timeLineCurMode; ETimeLineMode timeLineResMode; - bool hasProcessByRowFunc; + int32_t lastProcessByRowFuncId; bool timeLineFromOrderBy; bool isEmptyResult; bool isSubquery; diff --git a/include/util/taoserror.h b/include/util/taoserror.h index 2de336d036..38197c8504 100644 --- a/include/util/taoserror.h +++ b/include/util/taoserror.h @@ -831,6 +831,7 @@ int32_t taosGetErrSize(); #define TSDB_CODE_PAR_TBNAME_ERROR TAOS_DEF_ERROR_CODE(0, 0x267D) #define TSDB_CODE_PAR_TBNAME_DUPLICATED TAOS_DEF_ERROR_CODE(0, 0x267E) #define TSDB_CODE_PAR_TAG_NAME_DUPLICATED TAOS_DEF_ERROR_CODE(0, 0x267F) +#define TSDB_CODE_PAR_NOT_ALLOWED_DIFFERENT_BY_ROW_FUNC TAOS_DEF_ERROR_CODE(0, 0x2680) #define TSDB_CODE_PAR_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x26FF) //planner diff --git a/source/libs/function/src/builtinsimpl.c b/source/libs/function/src/builtinsimpl.c index c730aa334b..7d40aacdf7 100644 --- a/source/libs/function/src/builtinsimpl.c +++ b/source/libs/function/src/builtinsimpl.c @@ -3183,10 +3183,13 @@ static int32_t diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) return v < pDiffInfo->prev.i64; } case TSDB_DATA_TYPE_TIMESTAMP: - case TSDB_DATA_TYPE_UBIGINT: + case TSDB_DATA_TYPE_UBIGINT:{ + uint64_t v = *(uint64_t*)pv; + return v < (uint64_t)pDiffInfo->prev.i64; + } case TSDB_DATA_TYPE_BIGINT: { int64_t v = *(int64_t*)pv; - return v - pDiffInfo->prev.i64 < 0; + return v < pDiffInfo->prev.i64; } case TSDB_DATA_TYPE_FLOAT: { float v = *(float*)pv; @@ -3203,9 +3206,13 @@ static int32_t diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv) return false; } -static void tryToSetInt64(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, int64_t v, int32_t pos) { - int64_t delta = v - pDiffInfo->prev.i64; // direct previous may be null - if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) { +static void tryToSetInt64(SDiffInfo* pDiffInfo, int32_t type, SColumnInfoData* pOutput, int64_t v, int32_t pos) { + bool isNegative = v < pDiffInfo->prev.i64; + if(type == TSDB_DATA_TYPE_UBIGINT || type == TSDB_DATA_TYPE_TIMESTAMP){ + isNegative = (uint64_t)v < (uint64_t)pDiffInfo->prev.i64; + } + int64_t delta = v - pDiffInfo->prev.i64; + if (isNegative && ignoreNegative(pDiffInfo->ignoreOption)) { colDataSetNull_f_s(pOutput, pos); pOutput->hasNull = true; } else { @@ -3214,6 +3221,16 @@ static void tryToSetInt64(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, int64_ pDiffInfo->prev.i64 = v; } +static void tryToSetDouble(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, double v, int32_t pos) { + double delta = v - pDiffInfo->prev.d64; + if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) { + colDataSetNull_f_s(pOutput, pos); + } else { + colDataSetDouble(pOutput, pos, &delta); + } + pDiffInfo->prev.d64 = v; +} + static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos, int64_t ts) { if (!pDiffInfo->hasPrev) { @@ -3224,74 +3241,54 @@ static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, switch (type) { case TSDB_DATA_TYPE_UINT: { int64_t v = *(uint32_t*)pv; - tryToSetInt64(pDiffInfo, pOutput, v, pos); + tryToSetInt64(pDiffInfo, type, pOutput, v, pos); break; } case TSDB_DATA_TYPE_INT: { int64_t v = *(int32_t*)pv; - tryToSetInt64(pDiffInfo, pOutput, v, pos); + tryToSetInt64(pDiffInfo, type, pOutput, v, pos); break; } case TSDB_DATA_TYPE_BOOL: { int64_t v = *(bool*)pv; - tryToSetInt64(pDiffInfo, pOutput, v, pos); + tryToSetInt64(pDiffInfo, type, pOutput, v, pos); break; } case TSDB_DATA_TYPE_UTINYINT: { int64_t v = *(uint8_t*)pv; - tryToSetInt64(pDiffInfo, pOutput, v, pos); + tryToSetInt64(pDiffInfo, type, pOutput, v, pos); break; } case TSDB_DATA_TYPE_TINYINT: { int64_t v = *(int8_t*)pv; - tryToSetInt64(pDiffInfo, pOutput, v, pos); + tryToSetInt64(pDiffInfo, type, pOutput, v, pos); break; } case TSDB_DATA_TYPE_USMALLINT:{ int64_t v = *(uint16_t*)pv; - tryToSetInt64(pDiffInfo, pOutput, v, pos); + tryToSetInt64(pDiffInfo, type, pOutput, v, pos); break; } case TSDB_DATA_TYPE_SMALLINT: { int64_t v = *(int16_t*)pv; - tryToSetInt64(pDiffInfo, pOutput, v, pos); + tryToSetInt64(pDiffInfo, type, pOutput, v, pos); break; } case TSDB_DATA_TYPE_TIMESTAMP: case TSDB_DATA_TYPE_UBIGINT: case TSDB_DATA_TYPE_BIGINT: { int64_t v = *(int64_t*)pv; - int64_t delta = v - pDiffInfo->prev.i64; // direct previous may be null - if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) { - colDataSetNull_f_s(pOutput, pos); - } else { - colDataSetInt64(pOutput, pos, &delta); - } - pDiffInfo->prev.i64 = v; + tryToSetInt64(pDiffInfo, type, pOutput, v, pos); break; } case TSDB_DATA_TYPE_FLOAT: { double v = *(float*)pv; - double delta = v - pDiffInfo->prev.d64; // direct previous may be null - if ((delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) || isinf(delta) || - isnan(delta)) { // check for overflow - colDataSetNull_f_s(pOutput, pos); - } else { - colDataSetDouble(pOutput, pos, &delta); - } - pDiffInfo->prev.d64 = v; + tryToSetDouble(pDiffInfo, pOutput, v, pos); break; } case TSDB_DATA_TYPE_DOUBLE: { double v = *(double*)pv; - double delta = v - pDiffInfo->prev.d64; // direct previous may be null - if ((delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) || isinf(delta) || - isnan(delta)) { // check for overflow - colDataSetNull_f_s(pOutput, pos); - } else { - colDataSetDouble(pOutput, pos, &delta); - } - pDiffInfo->prev.d64 = v; + tryToSetDouble(pDiffInfo, pOutput, v, pos); break; } default: diff --git a/source/libs/parser/src/parTranslater.c b/source/libs/parser/src/parTranslater.c index 35c42e2ffb..85e148fece 100644 --- a/source/libs/parser/src/parTranslater.c +++ b/source/libs/parser/src/parTranslater.c @@ -2199,9 +2199,12 @@ static int32_t translateIndefiniteRowsFunc(STranslateContext* pCxt, SFunctionNod } if (pSelect->hasIndefiniteRowsFunc && (FUNC_RETURN_ROWS_INDEFINITE == pSelect->returnRows || pSelect->returnRows != fmGetFuncReturnRows(pFunc)) && - (!pSelect->hasProcessByRowFunc || !fmIsProcessByRowFunc(pFunc->funcId))) { + (pSelect->lastProcessByRowFuncId == -1 || !fmIsProcessByRowFunc(pFunc->funcId))) { return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC); } + if (pSelect->lastProcessByRowFuncId != -1 && pSelect->lastProcessByRowFuncId != pFunc->funcId) { + return generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_DIFFERENT_BY_ROW_FUNC); + } if (NULL != pSelect->pWindow || NULL != pSelect->pGroupByList) { return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, "%s function is not supported in window query or group query", pFunc->functionName); @@ -2466,7 +2469,7 @@ static void setFuncClassification(SNode* pCurrStmt, SFunctionNode* pFunc) { pSelect->returnRows = fmGetFuncReturnRows(pFunc); } if (fmIsProcessByRowFunc(pFunc->funcId)) { - pSelect->hasProcessByRowFunc = true; + pSelect->lastProcessByRowFuncId = pFunc->funcId; } pSelect->hasMultiRowsFunc = pSelect->hasMultiRowsFunc ? true : fmIsMultiRowsFunc(pFunc->funcId); @@ -3404,6 +3407,7 @@ static int32_t checkIsEmptyResult(STranslateContext* pCxt, SSelectStmt* pSelect) static int32_t resetSelectFuncNumWithoutDup(SSelectStmt* pSelect) { if (pSelect->selectFuncNum <= 1) return TSDB_CODE_SUCCESS; pSelect->selectFuncNum = 0; + pSelect->lastProcessByRowFuncId = -1; SNodeList* pNodeList = nodesMakeList(); int32_t code = nodesCollectSelectFuncs(pSelect, SQL_CLAUSE_FROM, NULL, fmIsSelectFunc, pNodeList); if (TSDB_CODE_SUCCESS != code) { diff --git a/source/libs/parser/src/parUtil.c b/source/libs/parser/src/parUtil.c index 416faafe35..d67c7d306f 100644 --- a/source/libs/parser/src/parUtil.c +++ b/source/libs/parser/src/parUtil.c @@ -221,6 +221,8 @@ static char* getSyntaxErrFormat(int32_t errCode) { return "Table name:%s duplicated"; case TSDB_CODE_PAR_TAG_NAME_DUPLICATED: return "Tag name:%s duplicated"; + case TSDB_CODE_PAR_NOT_ALLOWED_DIFFERENT_BY_ROW_FUNC: + return "Some functions cannot appear in the select list at the same time"; default: return "Unknown error"; } @@ -772,6 +774,7 @@ SNode* createSelectStmtImpl(bool isDistinct, SNodeList* pProjectionList, SNode* select->onlyHasKeepOrderFunc = true; select->timeRange = TSWINDOW_INITIALIZER; select->pHint = pHint; + select->lastProcessByRowFuncId = -1; return (SNode*)select; } diff --git a/source/util/src/terror.c b/source/util/src/terror.c index c5bba6fa53..dd1aeff5a2 100644 --- a/source/util/src/terror.c +++ b/source/util/src/terror.c @@ -678,6 +678,7 @@ TAOS_DEFINE_ERROR(TSDB_CODE_PAR_PRIMARY_KEY_IS_NONE, "Primary key column TAOS_DEFINE_ERROR(TSDB_CODE_PAR_TBNAME_ERROR, "Pseudo tag tbname not set") TAOS_DEFINE_ERROR(TSDB_CODE_PAR_TBNAME_DUPLICATED, "Table name duplicated") TAOS_DEFINE_ERROR(TSDB_CODE_PAR_TAG_NAME_DUPLICATED, "Tag name duplicated") +TAOS_DEFINE_ERROR(TSDB_CODE_PAR_NOT_ALLOWED_DIFFERENT_BY_ROW_FUNC, "Some functions cannot appear in the select list at the same time") TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INTERNAL_ERROR, "Parser internal error") //planner diff --git a/tests/system-test/2-query/diff.py b/tests/system-test/2-query/diff.py index 4400e8c26d..fd7ef00680 100644 --- a/tests/system-test/2-query/diff.py +++ b/tests/system-test/2-query/diff.py @@ -275,7 +275,7 @@ class TDTestCase: tdSql.checkRows(2) - def typeOverflowTest(self): + def intOverflowTest(self): dbname = "db" ts1 = 1694912400000 @@ -284,7 +284,7 @@ class TDTestCase: tdSql.execute(f"insert into {dbname}.stb6_1 values(%d, -2147483648, -32768, 0, 9223372036854775806, 9223372036854775806)" % (ts1 + 1)) tdSql.execute(f"insert into {dbname}.stb6_1 values(%d, 2147483647, 32767, 4294967295, 0, 0)" % (ts1 + 2)) - tdSql.execute(f"insert into {dbname}.stb6_1 values(%d, -10, -10, 0, -9223372036854775806, 9223372036854775806)" % (ts1 + 3)) + tdSql.execute(f"insert into {dbname}.stb6_1 values(%d, -10, -10, 0, -9223372036854775806, 16223372036854775806)" % (ts1 + 3)) tdSql.query(f"select ts, diff(c1), diff(c2), diff(c3), diff(c4), diff(c5) from {dbname}.stb6_1") tdSql.checkRows(2) @@ -299,7 +299,6 @@ class TDTestCase: tdSql.checkData(1, 2, -32777) tdSql.checkData(1, 3, -4294967295) tdSql.checkData(1, 4, -9223372036854775806) - tdSql.checkData(1, 5, 9223372036854775806) tdSql.query(f"select ts, diff(c1, 1), diff(c2) from {dbname}.stb6_1") tdSql.checkRows(2) @@ -326,6 +325,65 @@ class TDTestCase: tdSql.checkRows(1) tdSql.checkData(0, 1, 4294967295) tdSql.checkData(0, 2, 65535) + + tdSql.execute(f"insert into {dbname}.stb6_1 values(%d, -10, -10, 0, 9223372036854775800, 0)" % (ts1 + 4)) + tdSql.execute(f"insert into {dbname}.stb6_1 values(%d, -10, -10, 0, 9223372036854775800, 16223372036854775806)" % (ts1 + 5)) + + tdSql.query(f"select ts, diff(c4, 0) from {dbname}.stb6_1") + tdSql.checkRows(4) + + tdSql.query(f"select ts, diff(c4, 1) from {dbname}.stb6_1") + tdSql.checkRows(4) + tdSql.checkData(2, 1, -10) + + tdSql.query(f"select ts, diff(c4, 2) from {dbname}.stb6_1") + tdSql.checkRows(4) + + tdSql.query(f"select ts, diff(c4, 3) from {dbname}.stb6_1") + tdSql.checkRows(2) + tdSql.checkData(0, 1, -10) + tdSql.checkData(1, 1, 0) + + tdSql.query(f"select ts, diff(c5, 0) from {dbname}.stb6_1") + tdSql.checkRows(4) + + tdSql.query(f"select ts, diff(c5, 1) from {dbname}.stb6_1") + tdSql.checkRows(4) + tdSql.checkData(0, 1, None) + tdSql.checkData(1, 0, '2023-09-17 09:00:00.003') + tdSql.checkData(2, 1, None) + tdSql.checkData(3, 0, '2023-09-17 09:00:00.005') + + tdSql.query(f"select ts, diff(c5, 2) from {dbname}.stb6_1") + tdSql.checkRows(4) + + tdSql.query(f"select ts, diff(c5, 3) from {dbname}.stb6_1") + tdSql.checkRows(2) + tdSql.checkData(0, 0, '2023-09-17 09:00:00.003') + tdSql.checkData(1, 0, '2023-09-17 09:00:00.005') + + def doubleOverflowTest(self): + dbname = "db" + + ts1 = 1694912400000 + tdSql.execute(f'''create table {dbname}.stb7(ts timestamp, c1 float, c2 double) tags(loc nchar(20))''') + tdSql.execute(f"create table {dbname}.stb7_1 using {dbname}.stb7 tags('shanghai')") + + tdSql.execute(f"insert into {dbname}.stb7_1 values(%d, 334567777777777777777343434343333333733, 334567777777777777777343434343333333733)" % (ts1 + 1)) + tdSql.execute(f"insert into {dbname}.stb7_1 values(%d, -334567777777777777777343434343333333733, -334567777777777777777343434343333333733)" % (ts1 + 2)) + tdSql.execute(f"insert into {dbname}.stb7_1 values(%d, 334567777777777777777343434343333333733, 334567777777777777777343434343333333733)" % (ts1 + 3)) + + tdSql.query(f"select ts, diff(c1), diff(c2) from {dbname}.stb7_1") + tdSql.checkRows(2) + + tdSql.query(f"select ts, diff(c1, 1), diff(c2, 1) from {dbname}.stb7_1") + tdSql.checkRows(2) + tdSql.checkData(0, 1, None) + tdSql.checkData(0, 2, None) + + tdSql.query(f"select ts, diff(c1, 3), diff(c2, 3) from {dbname}.stb7_1") + tdSql.checkRows(1) + tdSql.checkData(0, 0, '2023-09-17 09:00:00.003') def run(self): tdSql.prepare() @@ -336,7 +394,8 @@ class TDTestCase: self.ignoreTest() self.withPkTest() - self.typeOverflowTest() + self.intOverflowTest() + self.doubleOverflowTest() tdSql.execute( f"create table {dbname}.ntb(ts timestamp,c1 int,c2 double,c3 float)")