Tarantool development patches archive
 help / color / mirror / Atom feed
* [Tarantool-patches] [PATCH v1 1/1] sql: fix cast of small negative DOUBLE to INTEGER
@ 2021-07-29  6:45 Mergen Imeev via Tarantool-patches
  0 siblings, 0 replies; 10+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-07-29  6:45 UTC (permalink / raw)
  To: tsafin; +Cc: tarantool-patches

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


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Tarantool-patches] [PATCH v1 1/1] sql: fix cast of small negative DOUBLE to INTEGER
  2021-08-04  8:24 Mergen Imeev via Tarantool-patches
  2021-08-04 14:02 ` Kirill Yukhin via Tarantool-patches
@ 2021-08-05  9:36 ` Kirill Yukhin via Tarantool-patches
  1 sibling, 0 replies; 10+ messages in thread
From: Kirill Yukhin via Tarantool-patches @ 2021-08-05  9:36 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Tarantool-patches]  [PATCH v1 1/1] sql: fix cast of small negative DOUBLE to INTEGER
  2021-08-04 14:02 ` Kirill Yukhin via Tarantool-patches
@ 2021-08-04 15:07   ` Vitaliia Ioffe via Tarantool-patches
  0 siblings, 0 replies; 10+ messages in thread
From: Vitaliia Ioffe via Tarantool-patches @ 2021-08-04 15:07 UTC (permalink / raw)
  To: tarantool-patches

[-- 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 --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Tarantool-patches] [PATCH v1 1/1] sql: fix cast of small negative DOUBLE to INTEGER
  2021-08-04  8:24 Mergen Imeev via Tarantool-patches
@ 2021-08-04 14:02 ` Kirill Yukhin via Tarantool-patches
  2021-08-04 15:07   ` Vitaliia Ioffe via Tarantool-patches
  2021-08-05  9:36 ` Kirill Yukhin via Tarantool-patches
  1 sibling, 1 reply; 10+ messages in thread
From: Kirill Yukhin via Tarantool-patches @ 2021-08-04 14:02 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Tarantool-patches] [PATCH v1 1/1] sql: fix cast of small negative DOUBLE to INTEGER
@ 2021-08-04  8:24 Mergen Imeev via Tarantool-patches
  2021-08-04 14:02 ` Kirill Yukhin via Tarantool-patches
  2021-08-05  9:36 ` Kirill Yukhin via Tarantool-patches
  0 siblings, 2 replies; 10+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-04  8:24 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

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


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Tarantool-patches] [PATCH v1 1/1] sql: fix cast of small negative DOUBLE to INTEGER
@ 2021-08-02 17:04 Mergen Imeev via Tarantool-patches
  0 siblings, 0 replies; 10+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-02 17:04 UTC (permalink / raw)
  To: imun; +Cc: tarantool-patches

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


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Tarantool-patches] [PATCH v1 1/1] sql: fix cast of small negative DOUBLE to INTEGER
  2021-07-27  8:09   ` Mergen Imeev via Tarantool-patches
@ 2021-07-28 21:55     ` Vladislav Shpilevoy via Tarantool-patches
  0 siblings, 0 replies; 10+ messages in thread
From: Vladislav Shpilevoy via Tarantool-patches @ 2021-07-28 21:55 UTC (permalink / raw)
  To: Mergen Imeev; +Cc: tarantool-patches

Hi! Thanks for the patch!

LGTM.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Tarantool-patches] [PATCH v1 1/1] sql: fix cast of small negative DOUBLE to INTEGER
  2021-07-26 19:47 ` Vladislav Shpilevoy via Tarantool-patches
@ 2021-07-27  8:09   ` Mergen Imeev via Tarantool-patches
  2021-07-28 21:55     ` Vladislav Shpilevoy via Tarantool-patches
  0 siblings, 1 reply; 10+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-07-27  8:09 UTC (permalink / raw)
  To: Vladislav Shpilevoy; +Cc: tarantool-patches

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.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Tarantool-patches] [PATCH v1 1/1] sql: fix cast of small negative DOUBLE to INTEGER
  2021-07-21 15:07 Mergen Imeev via Tarantool-patches
@ 2021-07-26 19:47 ` Vladislav Shpilevoy via Tarantool-patches
  2021-07-27  8:09   ` Mergen Imeev via Tarantool-patches
  0 siblings, 1 reply; 10+ messages in thread
From: Vladislav Shpilevoy via Tarantool-patches @ 2021-07-26 19:47 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

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?

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Tarantool-patches] [PATCH v1 1/1] sql: fix cast of small negative DOUBLE to INTEGER
@ 2021-07-21 15:07 Mergen Imeev via Tarantool-patches
  2021-07-26 19:47 ` Vladislav Shpilevoy via Tarantool-patches
  0 siblings, 1 reply; 10+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-07-21 15:07 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: tarantool-patches

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


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2021-08-05  9:37 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-29  6:45 [Tarantool-patches] [PATCH v1 1/1] sql: fix cast of small negative DOUBLE to INTEGER Mergen Imeev via Tarantool-patches
  -- strict thread matches above, loose matches on Subject: below --
2021-08-04  8:24 Mergen Imeev via Tarantool-patches
2021-08-04 14:02 ` Kirill Yukhin via Tarantool-patches
2021-08-04 15:07   ` Vitaliia Ioffe via Tarantool-patches
2021-08-05  9:36 ` Kirill Yukhin via Tarantool-patches
2021-08-02 17:04 Mergen Imeev via Tarantool-patches
2021-07-21 15:07 Mergen Imeev via Tarantool-patches
2021-07-26 19:47 ` Vladislav Shpilevoy via Tarantool-patches
2021-07-27  8:09   ` Mergen Imeev via Tarantool-patches
2021-07-28 21:55     ` Vladislav Shpilevoy via Tarantool-patches

Tarantool development patches archive

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://lists.tarantool.org/tarantool-patches/0 tarantool-patches/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 tarantool-patches tarantool-patches/ https://lists.tarantool.org/tarantool-patches \
		tarantool-patches@dev.tarantool.org.
	public-inbox-index tarantool-patches

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git