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-21 15:07 Mergen Imeev via Tarantool-patches
  0 siblings, 0 replies; only message 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] only message in thread

only message in thread, other threads:[~2021-07-21 15:07 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-21 15:07 [Tarantool-patches] [PATCH v1 1/1] sql: fix cast of small negative DOUBLE to INTEGER Mergen Imeev 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