Tarantool development patches archive
 help / color / mirror / Atom feed
From: Mergen Imeev via Tarantool-patches <tarantool-patches@dev.tarantool.org>
To: imun@tarantool.org
Cc: tarantool-patches@dev.tarantool.org
Subject: [Tarantool-patches] [PATCH v1 1/1] sql: fix cast of small negative DOUBLE to INTEGER
Date: Mon,  2 Aug 2021 20:04:32 +0300	[thread overview]
Message-ID: <66071c382ca0f49c34c4c65fb333fb99aee50f80.1627923808.git.imeevma@gmail.com> (raw)

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


             reply	other threads:[~2021-08-02 17:04 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-02 17:04 Mergen Imeev via Tarantool-patches [this message]
  -- 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-07-29  6:45 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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=66071c382ca0f49c34c4c65fb333fb99aee50f80.1627923808.git.imeevma@gmail.com \
    --to=tarantool-patches@dev.tarantool.org \
    --cc=imeevma@tarantool.org \
    --cc=imun@tarantool.org \
    --subject='Re: [Tarantool-patches] [PATCH v1 1/1] sql: fix cast of small negative DOUBLE to INTEGER' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox