Prior to this patch when DOUBLE value that less than 0.0 and greater than -1.0 was cast to INTEGER, it was considered to be negative number though the result was 0. This patch fixes this, so now such DOUBLE value will be properly cast to INTEGER and UNSIGNED. Closes #6225 --- https://github.com/tarantool/tarantool/issues/6225 https://github.com/tarantool/tarantool/tree/imeevma/gh-6225-cast-of-small-negative-double-to-int ...225-cast-of-small-negative-double-to-int.md | 4 ++++ src/box/sql/mem.c | 18 +++++++++--------- test/sql-tap/numcast.test.lua | 14 +++++++++++++- 3 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md diff --git a/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md b/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md new file mode 100644 index 000000000..9f5d62231 --- /dev/null +++ b/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md @@ -0,0 +1,4 @@ +## bugfix/sql + +* Fixed assert on cast of DOUBLE value that greater than -1.0 and less than 0.0 + to INTEGER and UNSIGNED (gh-6255). diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c index e4ce233e0..6b95e41d3 100644 --- a/src/box/sql/mem.c +++ b/src/box/sql/mem.c @@ -787,14 +787,14 @@ double_to_int(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d < 0 && d >= (double)INT64_MIN) { + if (d <= -1.0 && d >= (double)INT64_MIN) { mem->u.i = (int64_t)d; mem->type = MEM_TYPE_INT; assert(mem->flags == 0); mem->field_type = FIELD_TYPE_INTEGER; return 0; } - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -809,14 +809,14 @@ double_to_int_precise(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d < 0 && d >= (double)INT64_MIN && (double)(int64_t)d == d) { + if (d <= -1.0 && d >= (double)INT64_MIN && (double)(int64_t)d == d) { mem->u.i = (int64_t)d; mem->type = MEM_TYPE_INT; assert(mem->flags == 0); mem->field_type = FIELD_TYPE_INTEGER; return 0; } - if (d >= 0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { + if (d > -1.0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -831,7 +831,7 @@ double_to_uint(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -846,7 +846,7 @@ double_to_uint_precise(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d >= 0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { + if (d > -1.0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -1289,12 +1289,12 @@ mem_get_int(const struct Mem *mem, int64_t *i, bool *is_neg) return sql_atoi64(mem->z, i, is_neg, mem->n); if (mem->type == MEM_TYPE_DOUBLE) { double d = mem->u.r; - if (d < 0 && d >= (double)INT64_MIN) { + if (d <= -1.0 && d >= (double)INT64_MIN) { *i = (int64_t)d; *is_neg = true; return 0; } - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { *i = (int64_t)(uint64_t)d; *is_neg = false; return 0; @@ -1322,7 +1322,7 @@ mem_get_uint(const struct Mem *mem, uint64_t *u) } if (mem->type == MEM_TYPE_DOUBLE) { double d = mem->u.r; - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { *u = (uint64_t)d; return 0; } diff --git a/test/sql-tap/numcast.test.lua b/test/sql-tap/numcast.test.lua index 20aea3c4b..56b11da25 100755 --- a/test/sql-tap/numcast.test.lua +++ b/test/sql-tap/numcast.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool local test = require("sqltester") -test:plan(32) +test:plan(33) --!./tcltestrunner.lua -- 2013 March 20 @@ -261,4 +261,16 @@ test:do_catchsql_test( 1, "Type mismatch: can not convert double(-2.5) to unsigned" }) +-- +-- gh-6225: Make sure negative DOUBLE is greater than -1.0 and less than 0.0 can +-- be converted to INTEGER and UNSIGNED. +-- +test:do_execsql_test( + "numcast-5", + [[ + SELECT CAST(-0.999 AS INTEGER), CAST(-0.111 AS UNSIGNED); + ]], { + 0, 0 +}) + test:finish_test() -- 2.25.1
Thanks for the patch! > diff --git a/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md b/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md > new file mode 100644 > index 000000000..9f5d62231 > --- /dev/null > +++ b/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md > @@ -0,0 +1,4 @@ > +## bugfix/sql > + > +* Fixed assert on cast of DOUBLE value that greater than -1.0 and less than 0.0 > + to INTEGER and UNSIGNED (gh-6255). 1. I tried to revert the patch and only got an error, not an assertion. > diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c > index e4ce233e0..6b95e41d3 100644 > --- a/src/box/sql/mem.c > +++ b/src/box/sql/mem.c > @@ -1322,7 +1322,7 @@ mem_get_uint(const struct Mem *mem, uint64_t *u) > } > if (mem->type == MEM_TYPE_DOUBLE) { > double d = mem->u.r; > - if (d >= 0 && d < (double)UINT64_MAX) { > + if (d > -1.0 && d < (double)UINT64_MAX) { 2. I see there are 6 changes extending 0 to -1.0, but only 2 tests. Can you cover all the changed places?
Hi! Thank you for the review! My answers below. On Mon, Jul 26, 2021 at 09:47:21PM +0200, Vladislav Shpilevoy wrote: > Thanks for the patch! > > > diff --git a/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md b/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md > > new file mode 100644 > > index 000000000..9f5d62231 > > --- /dev/null > > +++ b/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md > > @@ -0,0 +1,4 @@ > > +## bugfix/sql > > + > > +* Fixed assert on cast of DOUBLE value that greater than -1.0 and less than 0.0 > > + to INTEGER and UNSIGNED (gh-6255). > > 1. I tried to revert the patch and only got an error, not an assertion. This is because I rebased this patch above "sql: disallow cast of negative DOUBLE to UNSIGNED". You can get an assert if you cast to INTEGER instead. > > > diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c > > index e4ce233e0..6b95e41d3 100644 > > --- a/src/box/sql/mem.c > > +++ b/src/box/sql/mem.c > > @@ -1322,7 +1322,7 @@ mem_get_uint(const struct Mem *mem, uint64_t *u) > > } > > if (mem->type == MEM_TYPE_DOUBLE) { > > double d = mem->u.r; > > - if (d >= 0 && d < (double)UINT64_MAX) { > > + if (d > -1.0 && d < (double)UINT64_MAX) { > > 2. I see there are 6 changes extending 0 to -1.0, but only 2 > tests. Can you cover all the changed places? I tried bo find a test, but this is quite problematic: For double_to_int_precise()/double_to_uint_precise() it actually does not matter since "(double)(uint64_t)d == d" check return false for any number greater than -1 and less than 0. I decided to change these functions so the first codition in IF would be unlinked to the third. For mem_get_int() it actually matters since it changes values of is_neg. However, this flag is ignored everywhere, so no test can be provided. Function mem_get_uint() is actually the only one, which wrongly returns -1 in case it gets double value that less than 0 and more than -1. However, the only case when this matters is actually inside of mem_get_uint_unsafe(), which returns 0 in case mem_get_uint() returns -1. Unexpectedly, this is the value that should be returned if mem_get_uint() gets a double value less than 0 and greater than -1. So this error is covered too.
Hi! Thanks for the patch! LGTM.
Prior to this patch when DOUBLE value that less than 0.0 and greater than -1.0 was cast to INTEGER, it was considered to be negative number though the result was 0. This patch fixes this, so now such DOUBLE value will be properly cast to INTEGER and UNSIGNED. Closes #6225 --- https://github.com/tarantool/tarantool/issues/6225 https://github.com/tarantool/tarantool/tree/imeevma/gh-6225-cast-of-small-negative-double-to-int ...225-cast-of-small-negative-double-to-int.md | 4 ++++ src/box/sql/mem.c | 18 +++++++++--------- test/sql-tap/numcast.test.lua | 14 +++++++++++++- 3 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md diff --git a/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md b/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md new file mode 100644 index 000000000..9f5d62231 --- /dev/null +++ b/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md @@ -0,0 +1,4 @@ +## bugfix/sql + +* Fixed assert on cast of DOUBLE value that greater than -1.0 and less than 0.0 + to INTEGER and UNSIGNED (gh-6255). diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c index e4ce233e0..6b95e41d3 100644 --- a/src/box/sql/mem.c +++ b/src/box/sql/mem.c @@ -787,14 +787,14 @@ double_to_int(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d < 0 && d >= (double)INT64_MIN) { + if (d <= -1.0 && d >= (double)INT64_MIN) { mem->u.i = (int64_t)d; mem->type = MEM_TYPE_INT; assert(mem->flags == 0); mem->field_type = FIELD_TYPE_INTEGER; return 0; } - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -809,14 +809,14 @@ double_to_int_precise(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d < 0 && d >= (double)INT64_MIN && (double)(int64_t)d == d) { + if (d <= -1.0 && d >= (double)INT64_MIN && (double)(int64_t)d == d) { mem->u.i = (int64_t)d; mem->type = MEM_TYPE_INT; assert(mem->flags == 0); mem->field_type = FIELD_TYPE_INTEGER; return 0; } - if (d >= 0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { + if (d > -1.0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -831,7 +831,7 @@ double_to_uint(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -846,7 +846,7 @@ double_to_uint_precise(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d >= 0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { + if (d > -1.0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -1289,12 +1289,12 @@ mem_get_int(const struct Mem *mem, int64_t *i, bool *is_neg) return sql_atoi64(mem->z, i, is_neg, mem->n); if (mem->type == MEM_TYPE_DOUBLE) { double d = mem->u.r; - if (d < 0 && d >= (double)INT64_MIN) { + if (d <= -1.0 && d >= (double)INT64_MIN) { *i = (int64_t)d; *is_neg = true; return 0; } - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { *i = (int64_t)(uint64_t)d; *is_neg = false; return 0; @@ -1322,7 +1322,7 @@ mem_get_uint(const struct Mem *mem, uint64_t *u) } if (mem->type == MEM_TYPE_DOUBLE) { double d = mem->u.r; - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { *u = (uint64_t)d; return 0; } diff --git a/test/sql-tap/numcast.test.lua b/test/sql-tap/numcast.test.lua index 20aea3c4b..56b11da25 100755 --- a/test/sql-tap/numcast.test.lua +++ b/test/sql-tap/numcast.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool local test = require("sqltester") -test:plan(32) +test:plan(33) --!./tcltestrunner.lua -- 2013 March 20 @@ -261,4 +261,16 @@ test:do_catchsql_test( 1, "Type mismatch: can not convert double(-2.5) to unsigned" }) +-- +-- gh-6225: Make sure negative DOUBLE is greater than -1.0 and less than 0.0 can +-- be converted to INTEGER and UNSIGNED. +-- +test:do_execsql_test( + "numcast-5", + [[ + SELECT CAST(-0.999 AS INTEGER), CAST(-0.111 AS UNSIGNED); + ]], { + 0, 0 +}) + test:finish_test() -- 2.25.1
Prior to this patch when DOUBLE value that less than 0.0 and greater than -1.0 was cast to INTEGER, it was considered to be negative number though the result was 0. This patch fixes this, so now such DOUBLE value will be properly cast to INTEGER and UNSIGNED. Closes #6225 --- https://github.com/tarantool/tarantool/issues/6225 https://github.com/tarantool/tarantool/tree/imeevma/gh-6225-cast-of-small-negative-double-to-int ...225-cast-of-small-negative-double-to-int.md | 4 ++++ src/box/sql/mem.c | 18 +++++++++--------- test/sql-tap/numcast.test.lua | 14 +++++++++++++- 3 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md diff --git a/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md b/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md new file mode 100644 index 000000000..9f5d62231 --- /dev/null +++ b/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md @@ -0,0 +1,4 @@ +## bugfix/sql + +* Fixed assert on cast of DOUBLE value that greater than -1.0 and less than 0.0 + to INTEGER and UNSIGNED (gh-6255). diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c index e4ce233e0..6b95e41d3 100644 --- a/src/box/sql/mem.c +++ b/src/box/sql/mem.c @@ -787,14 +787,14 @@ double_to_int(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d < 0 && d >= (double)INT64_MIN) { + if (d <= -1.0 && d >= (double)INT64_MIN) { mem->u.i = (int64_t)d; mem->type = MEM_TYPE_INT; assert(mem->flags == 0); mem->field_type = FIELD_TYPE_INTEGER; return 0; } - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -809,14 +809,14 @@ double_to_int_precise(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d < 0 && d >= (double)INT64_MIN && (double)(int64_t)d == d) { + if (d <= -1.0 && d >= (double)INT64_MIN && (double)(int64_t)d == d) { mem->u.i = (int64_t)d; mem->type = MEM_TYPE_INT; assert(mem->flags == 0); mem->field_type = FIELD_TYPE_INTEGER; return 0; } - if (d >= 0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { + if (d > -1.0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -831,7 +831,7 @@ double_to_uint(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -846,7 +846,7 @@ double_to_uint_precise(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d >= 0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { + if (d > -1.0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -1289,12 +1289,12 @@ mem_get_int(const struct Mem *mem, int64_t *i, bool *is_neg) return sql_atoi64(mem->z, i, is_neg, mem->n); if (mem->type == MEM_TYPE_DOUBLE) { double d = mem->u.r; - if (d < 0 && d >= (double)INT64_MIN) { + if (d <= -1.0 && d >= (double)INT64_MIN) { *i = (int64_t)d; *is_neg = true; return 0; } - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { *i = (int64_t)(uint64_t)d; *is_neg = false; return 0; @@ -1322,7 +1322,7 @@ mem_get_uint(const struct Mem *mem, uint64_t *u) } if (mem->type == MEM_TYPE_DOUBLE) { double d = mem->u.r; - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { *u = (uint64_t)d; return 0; } diff --git a/test/sql-tap/numcast.test.lua b/test/sql-tap/numcast.test.lua index 20aea3c4b..56b11da25 100755 --- a/test/sql-tap/numcast.test.lua +++ b/test/sql-tap/numcast.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool local test = require("sqltester") -test:plan(32) +test:plan(33) --!./tcltestrunner.lua -- 2013 March 20 @@ -261,4 +261,16 @@ test:do_catchsql_test( 1, "Type mismatch: can not convert double(-2.5) to unsigned" }) +-- +-- gh-6225: Make sure negative DOUBLE is greater than -1.0 and less than 0.0 can +-- be converted to INTEGER and UNSIGNED. +-- +test:do_execsql_test( + "numcast-5", + [[ + SELECT CAST(-0.999 AS INTEGER), CAST(-0.111 AS UNSIGNED); + ]], { + 0, 0 +}) + test:finish_test() -- 2.25.1
Prior to this patch when DOUBLE value that less than 0.0 and greater than -1.0 was cast to INTEGER, it was considered to be negative number though the result was 0. This patch fixes this, so now such DOUBLE value will be properly cast to INTEGER and UNSIGNED. Closes #6225 --- https://github.com/tarantool/tarantool/issues/6225 https://github.com/tarantool/tarantool/tree/imeevma/gh-6225-cast-of-small-negative-double-to-int ...225-cast-of-small-negative-double-to-int.md | 4 ++++ src/box/sql/mem.c | 18 +++++++++--------- test/sql-tap/numcast.test.lua | 14 +++++++++++++- 3 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md diff --git a/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md b/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md new file mode 100644 index 000000000..9f5d62231 --- /dev/null +++ b/changelogs/unreleased/gh-6225-cast-of-small-negative-double-to-int.md @@ -0,0 +1,4 @@ +## bugfix/sql + +* Fixed assert on cast of DOUBLE value that greater than -1.0 and less than 0.0 + to INTEGER and UNSIGNED (gh-6255). diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c index e4ce233e0..6b95e41d3 100644 --- a/src/box/sql/mem.c +++ b/src/box/sql/mem.c @@ -787,14 +787,14 @@ double_to_int(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d < 0 && d >= (double)INT64_MIN) { + if (d <= -1.0 && d >= (double)INT64_MIN) { mem->u.i = (int64_t)d; mem->type = MEM_TYPE_INT; assert(mem->flags == 0); mem->field_type = FIELD_TYPE_INTEGER; return 0; } - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -809,14 +809,14 @@ double_to_int_precise(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d < 0 && d >= (double)INT64_MIN && (double)(int64_t)d == d) { + if (d <= -1.0 && d >= (double)INT64_MIN && (double)(int64_t)d == d) { mem->u.i = (int64_t)d; mem->type = MEM_TYPE_INT; assert(mem->flags == 0); mem->field_type = FIELD_TYPE_INTEGER; return 0; } - if (d >= 0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { + if (d > -1.0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -831,7 +831,7 @@ double_to_uint(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -846,7 +846,7 @@ double_to_uint_precise(struct Mem *mem) { assert(mem->type == MEM_TYPE_DOUBLE); double d = mem->u.r; - if (d >= 0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { + if (d > -1.0 && d < (double)UINT64_MAX && (double)(uint64_t)d == d) { mem->u.u = (uint64_t)d; mem->type = MEM_TYPE_UINT; assert(mem->flags == 0); @@ -1289,12 +1289,12 @@ mem_get_int(const struct Mem *mem, int64_t *i, bool *is_neg) return sql_atoi64(mem->z, i, is_neg, mem->n); if (mem->type == MEM_TYPE_DOUBLE) { double d = mem->u.r; - if (d < 0 && d >= (double)INT64_MIN) { + if (d <= -1.0 && d >= (double)INT64_MIN) { *i = (int64_t)d; *is_neg = true; return 0; } - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { *i = (int64_t)(uint64_t)d; *is_neg = false; return 0; @@ -1322,7 +1322,7 @@ mem_get_uint(const struct Mem *mem, uint64_t *u) } if (mem->type == MEM_TYPE_DOUBLE) { double d = mem->u.r; - if (d >= 0 && d < (double)UINT64_MAX) { + if (d > -1.0 && d < (double)UINT64_MAX) { *u = (uint64_t)d; return 0; } diff --git a/test/sql-tap/numcast.test.lua b/test/sql-tap/numcast.test.lua index 20aea3c4b..56b11da25 100755 --- a/test/sql-tap/numcast.test.lua +++ b/test/sql-tap/numcast.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool local test = require("sqltester") -test:plan(32) +test:plan(33) --!./tcltestrunner.lua -- 2013 March 20 @@ -261,4 +261,16 @@ test:do_catchsql_test( 1, "Type mismatch: can not convert double(-2.5) to unsigned" }) +-- +-- gh-6225: Make sure negative DOUBLE is greater than -1.0 and less than 0.0 can +-- be converted to INTEGER and UNSIGNED. +-- +test:do_execsql_test( + "numcast-5", + [[ + SELECT CAST(-0.999 AS INTEGER), CAST(-0.111 AS UNSIGNED); + ]], { + 0, 0 +}) + test:finish_test() -- 2.25.1
Hello,
On 04 авг 11:24, imeevma@tarantool.org wrote:
> Prior to this patch when DOUBLE value that less than 0.0 and greater
> than -1.0 was cast to INTEGER, it was considered to be negative number
> though the result was 0. This patch fixes this, so now such DOUBLE
> value will be properly cast to INTEGER and UNSIGNED.
>
> Closes #6225
> ---
> https://github.com/tarantool/tarantool/issues/6225
> https://github.com/tarantool/tarantool/tree/imeevma/gh-6225-cast-of-small-negative-double-to-int
The patch LGTM.
--
Regards, Kirill Yukhin
[-- Attachment #1: Type: text/plain, Size: 752 bytes --] Hi team, QA LGTM! -- Vitaliia Ioffe >Среда, 4 августа 2021, 17:02 +03:00 от Kirill Yukhin via Tarantool-patches <tarantool-patches@dev.tarantool.org>: > >Hello, > >On 04 авг 11:24, imeevma@tarantool.org wrote: >> Prior to this patch when DOUBLE value that less than 0.0 and greater >> than -1.0 was cast to INTEGER, it was considered to be negative number >> though the result was 0. This patch fixes this, so now such DOUBLE >> value will be properly cast to INTEGER and UNSIGNED. >> >> Closes #6225 >> --- >> https://github.com/tarantool/tarantool/issues/6225 >> https://github.com/tarantool/tarantool/tree/imeevma/gh-6225-cast-of-small-negative-double-to-int >The patch LGTM. > >-- >Regards, Kirill Yukhin [-- Attachment #2: Type: text/html, Size: 1558 bytes --]
Hello,
On 04 авг 11:24, imeevma@tarantool.org wrote:
> Prior to this patch when DOUBLE value that less than 0.0 and greater
> than -1.0 was cast to INTEGER, it was considered to be negative number
> though the result was 0. This patch fixes this, so now such DOUBLE
> value will be properly cast to INTEGER and UNSIGNED.
>
> Closes #6225
> ---
> https://github.com/tarantool/tarantool/issues/6225
> https://github.com/tarantool/tarantool/tree/imeevma/gh-6225-cast-of-small-negative-double-to-int
I've checked your patch into 2.7, 2.8 and master.
--
Regards, Kirill