fix: type overflow

This commit is contained in:
factosea 2024-07-09 14:48:21 +08:00
parent 20f4eda56d
commit 163b31a4ee
7 changed files with 107 additions and 42 deletions

View File

@ -415,7 +415,7 @@ typedef struct SSelectStmt {
int32_t returnRows; // EFuncReturnRows int32_t returnRows; // EFuncReturnRows
ETimeLineMode timeLineCurMode; ETimeLineMode timeLineCurMode;
ETimeLineMode timeLineResMode; ETimeLineMode timeLineResMode;
bool hasProcessByRowFunc; int32_t lastProcessByRowFuncId;
bool timeLineFromOrderBy; bool timeLineFromOrderBy;
bool isEmptyResult; bool isEmptyResult;
bool isSubquery; bool isSubquery;

View File

@ -831,6 +831,7 @@ int32_t taosGetErrSize();
#define TSDB_CODE_PAR_TBNAME_ERROR TAOS_DEF_ERROR_CODE(0, 0x267D) #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_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_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) #define TSDB_CODE_PAR_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x26FF)
//planner //planner

View File

@ -3183,10 +3183,13 @@ static int32_t diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv)
return v < pDiffInfo->prev.i64; return v < pDiffInfo->prev.i64;
} }
case TSDB_DATA_TYPE_TIMESTAMP: 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: { case TSDB_DATA_TYPE_BIGINT: {
int64_t v = *(int64_t*)pv; int64_t v = *(int64_t*)pv;
return v - pDiffInfo->prev.i64 < 0; return v < pDiffInfo->prev.i64;
} }
case TSDB_DATA_TYPE_FLOAT: { case TSDB_DATA_TYPE_FLOAT: {
float v = *(float*)pv; float v = *(float*)pv;
@ -3203,9 +3206,13 @@ static int32_t diffIsNegtive(SDiffInfo* pDiffInfo, int32_t type, const char* pv)
return false; return false;
} }
static void tryToSetInt64(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, int64_t v, int32_t pos) { static void tryToSetInt64(SDiffInfo* pDiffInfo, int32_t type, SColumnInfoData* pOutput, int64_t v, int32_t pos) {
int64_t delta = v - pDiffInfo->prev.i64; // direct previous may be null bool isNegative = v < pDiffInfo->prev.i64;
if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) { 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); colDataSetNull_f_s(pOutput, pos);
pOutput->hasNull = true; pOutput->hasNull = true;
} else { } else {
@ -3214,6 +3221,16 @@ static void tryToSetInt64(SDiffInfo* pDiffInfo, SColumnInfoData* pOutput, int64_
pDiffInfo->prev.i64 = v; 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, static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv, SColumnInfoData* pOutput, int32_t pos,
int64_t ts) { int64_t ts) {
if (!pDiffInfo->hasPrev) { if (!pDiffInfo->hasPrev) {
@ -3224,74 +3241,54 @@ static int32_t doHandleDiff(SDiffInfo* pDiffInfo, int32_t type, const char* pv,
switch (type) { switch (type) {
case TSDB_DATA_TYPE_UINT: { case TSDB_DATA_TYPE_UINT: {
int64_t v = *(uint32_t*)pv; int64_t v = *(uint32_t*)pv;
tryToSetInt64(pDiffInfo, pOutput, v, pos); tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
break; break;
} }
case TSDB_DATA_TYPE_INT: { case TSDB_DATA_TYPE_INT: {
int64_t v = *(int32_t*)pv; int64_t v = *(int32_t*)pv;
tryToSetInt64(pDiffInfo, pOutput, v, pos); tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
break; break;
} }
case TSDB_DATA_TYPE_BOOL: { case TSDB_DATA_TYPE_BOOL: {
int64_t v = *(bool*)pv; int64_t v = *(bool*)pv;
tryToSetInt64(pDiffInfo, pOutput, v, pos); tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
break; break;
} }
case TSDB_DATA_TYPE_UTINYINT: { case TSDB_DATA_TYPE_UTINYINT: {
int64_t v = *(uint8_t*)pv; int64_t v = *(uint8_t*)pv;
tryToSetInt64(pDiffInfo, pOutput, v, pos); tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
break; break;
} }
case TSDB_DATA_TYPE_TINYINT: { case TSDB_DATA_TYPE_TINYINT: {
int64_t v = *(int8_t*)pv; int64_t v = *(int8_t*)pv;
tryToSetInt64(pDiffInfo, pOutput, v, pos); tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
break; break;
} }
case TSDB_DATA_TYPE_USMALLINT:{ case TSDB_DATA_TYPE_USMALLINT:{
int64_t v = *(uint16_t*)pv; int64_t v = *(uint16_t*)pv;
tryToSetInt64(pDiffInfo, pOutput, v, pos); tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
break; break;
} }
case TSDB_DATA_TYPE_SMALLINT: { case TSDB_DATA_TYPE_SMALLINT: {
int64_t v = *(int16_t*)pv; int64_t v = *(int16_t*)pv;
tryToSetInt64(pDiffInfo, pOutput, v, pos); tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
break; break;
} }
case TSDB_DATA_TYPE_TIMESTAMP: case TSDB_DATA_TYPE_TIMESTAMP:
case TSDB_DATA_TYPE_UBIGINT: case TSDB_DATA_TYPE_UBIGINT:
case TSDB_DATA_TYPE_BIGINT: { case TSDB_DATA_TYPE_BIGINT: {
int64_t v = *(int64_t*)pv; int64_t v = *(int64_t*)pv;
int64_t delta = v - pDiffInfo->prev.i64; // direct previous may be null tryToSetInt64(pDiffInfo, type, pOutput, v, pos);
if (delta < 0 && ignoreNegative(pDiffInfo->ignoreOption)) {
colDataSetNull_f_s(pOutput, pos);
} else {
colDataSetInt64(pOutput, pos, &delta);
}
pDiffInfo->prev.i64 = v;
break; break;
} }
case TSDB_DATA_TYPE_FLOAT: { case TSDB_DATA_TYPE_FLOAT: {
double v = *(float*)pv; double v = *(float*)pv;
double delta = v - pDiffInfo->prev.d64; // direct previous may be null tryToSetDouble(pDiffInfo, pOutput, v, pos);
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;
break; break;
} }
case TSDB_DATA_TYPE_DOUBLE: { case TSDB_DATA_TYPE_DOUBLE: {
double v = *(double*)pv; double v = *(double*)pv;
double delta = v - pDiffInfo->prev.d64; // direct previous may be null tryToSetDouble(pDiffInfo, pOutput, v, pos);
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;
break; break;
} }
default: default:

View File

@ -2199,9 +2199,12 @@ static int32_t translateIndefiniteRowsFunc(STranslateContext* pCxt, SFunctionNod
} }
if (pSelect->hasIndefiniteRowsFunc && if (pSelect->hasIndefiniteRowsFunc &&
(FUNC_RETURN_ROWS_INDEFINITE == pSelect->returnRows || pSelect->returnRows != fmGetFuncReturnRows(pFunc)) && (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); 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) { if (NULL != pSelect->pWindow || NULL != pSelect->pGroupByList) {
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC, return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_NOT_ALLOWED_FUNC,
"%s function is not supported in window query or group query", pFunc->functionName); "%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); pSelect->returnRows = fmGetFuncReturnRows(pFunc);
} }
if (fmIsProcessByRowFunc(pFunc->funcId)) { if (fmIsProcessByRowFunc(pFunc->funcId)) {
pSelect->hasProcessByRowFunc = true; pSelect->lastProcessByRowFuncId = pFunc->funcId;
} }
pSelect->hasMultiRowsFunc = pSelect->hasMultiRowsFunc ? true : fmIsMultiRowsFunc(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) { static int32_t resetSelectFuncNumWithoutDup(SSelectStmt* pSelect) {
if (pSelect->selectFuncNum <= 1) return TSDB_CODE_SUCCESS; if (pSelect->selectFuncNum <= 1) return TSDB_CODE_SUCCESS;
pSelect->selectFuncNum = 0; pSelect->selectFuncNum = 0;
pSelect->lastProcessByRowFuncId = -1;
SNodeList* pNodeList = nodesMakeList(); SNodeList* pNodeList = nodesMakeList();
int32_t code = nodesCollectSelectFuncs(pSelect, SQL_CLAUSE_FROM, NULL, fmIsSelectFunc, pNodeList); int32_t code = nodesCollectSelectFuncs(pSelect, SQL_CLAUSE_FROM, NULL, fmIsSelectFunc, pNodeList);
if (TSDB_CODE_SUCCESS != code) { if (TSDB_CODE_SUCCESS != code) {

View File

@ -221,6 +221,8 @@ static char* getSyntaxErrFormat(int32_t errCode) {
return "Table name:%s duplicated"; return "Table name:%s duplicated";
case TSDB_CODE_PAR_TAG_NAME_DUPLICATED: case TSDB_CODE_PAR_TAG_NAME_DUPLICATED:
return "Tag name:%s 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: default:
return "Unknown error"; return "Unknown error";
} }
@ -772,6 +774,7 @@ SNode* createSelectStmtImpl(bool isDistinct, SNodeList* pProjectionList, SNode*
select->onlyHasKeepOrderFunc = true; select->onlyHasKeepOrderFunc = true;
select->timeRange = TSWINDOW_INITIALIZER; select->timeRange = TSWINDOW_INITIALIZER;
select->pHint = pHint; select->pHint = pHint;
select->lastProcessByRowFuncId = -1;
return (SNode*)select; return (SNode*)select;
} }

View File

@ -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_ERROR, "Pseudo tag tbname not set")
TAOS_DEFINE_ERROR(TSDB_CODE_PAR_TBNAME_DUPLICATED, "Table name duplicated") 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_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") TAOS_DEFINE_ERROR(TSDB_CODE_PAR_INTERNAL_ERROR, "Parser internal error")
//planner //planner

View File

@ -275,7 +275,7 @@ class TDTestCase:
tdSql.checkRows(2) tdSql.checkRows(2)
def typeOverflowTest(self): def intOverflowTest(self):
dbname = "db" dbname = "db"
ts1 = 1694912400000 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, -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, 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.query(f"select ts, diff(c1), diff(c2), diff(c3), diff(c4), diff(c5) from {dbname}.stb6_1")
tdSql.checkRows(2) tdSql.checkRows(2)
@ -299,7 +299,6 @@ class TDTestCase:
tdSql.checkData(1, 2, -32777) tdSql.checkData(1, 2, -32777)
tdSql.checkData(1, 3, -4294967295) tdSql.checkData(1, 3, -4294967295)
tdSql.checkData(1, 4, -9223372036854775806) 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.query(f"select ts, diff(c1, 1), diff(c2) from {dbname}.stb6_1")
tdSql.checkRows(2) tdSql.checkRows(2)
@ -327,6 +326,65 @@ class TDTestCase:
tdSql.checkData(0, 1, 4294967295) tdSql.checkData(0, 1, 4294967295)
tdSql.checkData(0, 2, 65535) 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): def run(self):
tdSql.prepare() tdSql.prepare()
dbname = "db" dbname = "db"
@ -336,7 +394,8 @@ class TDTestCase:
self.ignoreTest() self.ignoreTest()
self.withPkTest() self.withPkTest()
self.typeOverflowTest() self.intOverflowTest()
self.doubleOverflowTest()
tdSql.execute( tdSql.execute(
f"create table {dbname}.ntb(ts timestamp,c1 int,c2 double,c3 float)") f"create table {dbname}.ntb(ts timestamp,c1 int,c2 double,c3 float)")