diff --git a/source/client/src/clientSml.c b/source/client/src/clientSml.c index 884756ced91bc797d8cd715337c598343ae6752d..f6f8db859075dd8accff0e21efed38fc7ec0bb46 100644 --- a/source/client/src/clientSml.c +++ b/source/client/src/clientSml.c @@ -714,25 +714,31 @@ static bool smlIsNchar(const char *pVal, uint16_t len) { static int64_t smlGetTimeValue(const char *value, int32_t len, int8_t type) { char *endPtr = NULL; - double ts = (double)strtoll(value, &endPtr, 10); + int64_t tsInt64 = strtoll(value, &endPtr, 10); if(value + len != endPtr){ return -1; } + double ts = tsInt64; switch (type) { case TSDB_TIME_PRECISION_HOURS: ts *= (3600 * 1e9); + tsInt64 *= (3600 * 1e9); break; case TSDB_TIME_PRECISION_MINUTES: ts *= (60 * 1e9); + tsInt64 *= (60 * 1e9); break; case TSDB_TIME_PRECISION_SECONDS: ts *= (1e9); + tsInt64 *= (1e9); break; case TSDB_TIME_PRECISION_MILLI: ts *= (1e6); + tsInt64 *= (1e6); break; case TSDB_TIME_PRECISION_MICRO: ts *= (1e3); + tsInt64 *= (1e3); break; case TSDB_TIME_PRECISION_NANO: break; @@ -743,7 +749,7 @@ static int64_t smlGetTimeValue(const char *value, int32_t len, int8_t type) { return -1; } - return (int64_t)ts; + return tsInt64; } static int64_t smlGetTimeNow(int8_t precision) { diff --git a/source/client/test/smlTest.cpp b/source/client/test/smlTest.cpp index eeab844712eac59edf3bb689d1c7c2afb438e8fa..d9a81ad3e67e9a7ed793345a061eb94eb6e05439 100644 --- a/source/client/test/smlTest.cpp +++ b/source/client/test/smlTest.cpp @@ -1188,3 +1188,36 @@ TEST(testCase, smlParseTelnetLine_diff_json_type2_Test) { destroyRequest(request); smlDestroyInfo(info); } + +TEST(testCase, sml_TD15662_Test) { + TAOS *taos = taos_connect("localhost", "root", "taosdata", NULL, 0); + ASSERT_NE(taos, nullptr); + + TAOS_RES *pRes = taos_query(taos, "create database if not exists db_15662 precision 'ns'"); + taos_free_result(pRes); + + pRes = taos_query(taos, "use db_15662"); + taos_free_result(pRes); + + SRequestObj *request = (SRequestObj *)createRequest((STscObj *)taos, NULL, NULL, TSDB_SQL_INSERT); + ASSERT_NE(request, nullptr); + + SSmlHandle *info = smlBuildSmlInfo(taos, request, TSDB_SML_LINE_PROTOCOL, TSDB_SML_TIMESTAMP_NANO_SECONDS); + ASSERT_NE(info, nullptr); + + const char *sql[] = { + "iyyyje,id=iyyyje_41943_1303,t0=t,t1=127i8,t2=32767i16,t3=2147483647i32,t4=9223372036854775807i64,t5=11.12345f32,t6=22.123456789f64,t7=\"binaryTagValue\",t8=L\"ncharTagValue\" c0=false,c1=127i8,c2=32767i16,c3=2147483647i32,c4=9223372036854775807i64,c5=11.12345f32,c6=22.123456789f64,c7=\"binaryColValue\",c8=L\"ncharColValue\",c9=7u64 1626006833639000000", + }; + int ret = smlProcess(info, (char **)sql, sizeof(sql) / sizeof(sql[0])); + ASSERT_EQ(ret, 0); + + // case 1 + TAOS_RES *res = taos_query(taos, "select * from t_a5615048edae55218a22a149edebdc82"); + ASSERT_NE(res, nullptr); + + TAOS_ROW row = taos_fetch_row(res); + int64_t ts = *(int64_t*)row[0]; + ASSERT_EQ(ts, 1626006833639000000); + + taos_free_result(res); +} \ No newline at end of file diff --git a/source/common/src/ttime.c b/source/common/src/ttime.c index c2892c070f42fcff9324814a5486a6b191d667a3..62a71796262314d40a3f984b3933376370110605 100644 --- a/source/common/src/ttime.c +++ b/source/common/src/ttime.c @@ -374,39 +374,135 @@ char getPrecisionUnit(int32_t precision) { } int64_t convertTimePrecision(int64_t time, int32_t fromPrecision, int32_t toPrecision) { - assert(fromPrecision == TSDB_TIME_PRECISION_MILLI || fromPrecision == TSDB_TIME_PRECISION_MICRO || + assert(fromPrecision == TSDB_TIME_PRECISION_MILLI || + fromPrecision == TSDB_TIME_PRECISION_MICRO || fromPrecision == TSDB_TIME_PRECISION_NANO); - assert(toPrecision == TSDB_TIME_PRECISION_MILLI || toPrecision == TSDB_TIME_PRECISION_MICRO || + assert(toPrecision == TSDB_TIME_PRECISION_MILLI || + toPrecision == TSDB_TIME_PRECISION_MICRO || toPrecision == TSDB_TIME_PRECISION_NANO); - static double factors[3][3] = {{1., 1000., 1000000.}, {1.0 / 1000, 1., 1000.}, {1.0 / 1000000, 1.0 / 1000, 1.}}; - return (int64_t)((double)time * factors[fromPrecision][toPrecision]); + double tempResult = (double)time; + switch(fromPrecision) { + case TSDB_TIME_PRECISION_MILLI: { + switch (toPrecision) { + case TSDB_TIME_PRECISION_MILLI: + return time; + case TSDB_TIME_PRECISION_MICRO: + tempResult *= 1000; + time *= 1000; + goto end_; + case TSDB_TIME_PRECISION_NANO: + tempResult *= 1000000; + time *= 1000000; + goto end_; + } + } // end from milli + case TSDB_TIME_PRECISION_MICRO: { + switch (toPrecision) { + case TSDB_TIME_PRECISION_MILLI: + return time / 1000; + case TSDB_TIME_PRECISION_MICRO: + return time; + case TSDB_TIME_PRECISION_NANO: + tempResult *= 1000; + time *= 1000; + goto end_; + } + } //end from micro + case TSDB_TIME_PRECISION_NANO: { + switch (toPrecision) { + case TSDB_TIME_PRECISION_MILLI: + return time / 1000000; + case TSDB_TIME_PRECISION_MICRO: + return time / 1000; + case TSDB_TIME_PRECISION_NANO: + return time; + } + } //end from nano + default: { + assert(0); + return time; // only to pass windows compilation + } + } //end switch fromPrecision +end_: + if (tempResult >= (double)INT64_MAX) return INT64_MAX; + if (tempResult <= (double)INT64_MIN) return INT64_MIN; // INT64_MIN means NULL + return time; } +// !!!!notice:there are precision problems, double lose precison if time is too large, for example: 1626006833631000000*1.0 = double = 1626006833631000064 +//int64_t convertTimePrecision(int64_t time, int32_t fromPrecision, int32_t toPrecision) { +// assert(fromPrecision == TSDB_TIME_PRECISION_MILLI || fromPrecision == TSDB_TIME_PRECISION_MICRO || +// fromPrecision == TSDB_TIME_PRECISION_NANO); +// assert(toPrecision == TSDB_TIME_PRECISION_MILLI || toPrecision == TSDB_TIME_PRECISION_MICRO || +// toPrecision == TSDB_TIME_PRECISION_NANO); +// static double factors[3][3] = {{1., 1000., 1000000.}, {1.0 / 1000, 1., 1000.}, {1.0 / 1000000, 1.0 / 1000, 1.}}; +// ((double)time * factors[fromPrecision][toPrecision]); +//} + + +// !!!!notice: double lose precison if time is too large, for example: 1626006833631000000*1.0 = double = 1626006833631000064 int64_t convertTimeFromPrecisionToUnit(int64_t time, int32_t fromPrecision, char toUnit) { assert(fromPrecision == TSDB_TIME_PRECISION_MILLI || fromPrecision == TSDB_TIME_PRECISION_MICRO || fromPrecision == TSDB_TIME_PRECISION_NANO); - static double factors[3] = {1000000., 1000., 1.}; + int64_t factors[3] = {NANOSECOND_PER_MSEC, NANOSECOND_PER_USEC, 1}; + double tmp = time; switch (toUnit) { - case 's': - return time * factors[fromPrecision] / NANOSECOND_PER_SEC; + case 's':{ + tmp /= (NANOSECOND_PER_SEC/factors[fromPrecision]); // the result of division is an integer + time /= (NANOSECOND_PER_SEC/factors[fromPrecision]); + break; + } case 'm': - return time * factors[fromPrecision] / NANOSECOND_PER_MINUTE; + tmp /= (NANOSECOND_PER_MINUTE/factors[fromPrecision]); // the result of division is an integer + time /= (NANOSECOND_PER_MINUTE/factors[fromPrecision]); + break; case 'h': - return time * factors[fromPrecision] / NANOSECOND_PER_HOUR; + tmp /= (NANOSECOND_PER_HOUR/factors[fromPrecision]); // the result of division is an integer + time /= (NANOSECOND_PER_HOUR/factors[fromPrecision]); + break; case 'd': - return time * factors[fromPrecision] / NANOSECOND_PER_DAY; + tmp /= (NANOSECOND_PER_DAY/factors[fromPrecision]); // the result of division is an integer + time /= (NANOSECOND_PER_DAY/factors[fromPrecision]); + break; case 'w': - return time * factors[fromPrecision] / NANOSECOND_PER_WEEK; + tmp /= (NANOSECOND_PER_WEEK/factors[fromPrecision]); // the result of division is an integer + time /= (NANOSECOND_PER_WEEK/factors[fromPrecision]); + break; case 'a': - return time * factors[fromPrecision] / NANOSECOND_PER_MSEC; + tmp /= (NANOSECOND_PER_MSEC/factors[fromPrecision]); // the result of division is an integer + time /= (NANOSECOND_PER_MSEC/factors[fromPrecision]); + break; case 'u': - return time * factors[fromPrecision] / NANOSECOND_PER_USEC; + // the result of (NANOSECOND_PER_USEC/(double)factors[fromPrecision]) maybe a double + switch (fromPrecision) { + case TSDB_TIME_PRECISION_MILLI:{ + tmp *= 1000; + time *= 1000; + break; + } + case TSDB_TIME_PRECISION_MICRO:{ + tmp /= 1; + time /= 1; + break; + } + case TSDB_TIME_PRECISION_NANO:{ + tmp /= 1000; + time /= 1000; + break; + } + } + break; case 'b': - return time * factors[fromPrecision]; + tmp *= factors[fromPrecision]; + time *= factors[fromPrecision]; + break; default: { return -1; } } + if (tmp >= (double)INT64_MAX) return INT64_MAX; + if (tmp <= (double)INT64_MIN) return INT64_MIN; + return time; } int32_t convertStringToTimestamp(int16_t type, char *inputData, int64_t timePrec, int64_t *timeVal) {