Tarantool development patches archive
 help / color / mirror / Atom feed
From: imeevma@tarantool.org
To: korablev@tarantool.org, tsafin@tarantool.org,
	tarantool-patches@dev.tarantool.org
Subject: [Tarantool-patches] [PATCH v4 3/3] sql: add '\0' to the BLOB when it is cast to INTEGER
Date: Fri, 27 Mar 2020 14:33:43 +0300	[thread overview]
Message-ID: <3068e777d61da1f73764c68bc94074fe01119af9.1585308644.git.imeevma@gmail.com> (raw)
In-Reply-To: <cover.1585308644.git.imeevma@gmail.com>

Prior to this patch, due to the absence of the '\0' character at
the end of the BLOB, it was possible to get an error or incorrect
result when using CAST() from BLOB to INTEGER or UNSIGNED. This
has now been fixed, but the maximum length of a BLOB that could be
cast to INTEGER or UNSIGNED was limited to 12287 bytes.

Examples of wrong CAST() from BLOB to INTEGER:

CREATE TABLE t (i INT PRIMARY KEY, a VARBINARY, b INT, c INT);
INSERT INTO t VALUES (1, X'33', 0x33, 0x00), (2, X'34', 0x41, 0);

Example of wrong result:

SELECT CAST(a AS INTEGER) FROM t WHERE i = 1;

Result: 33

Example of error during CAST():

SELECT CAST(a AS INTEGER) FROM t WHERE i = 2;

Result: 'Type mismatch: can not convert varbinary to integer'

Closes #4766
---
 src/box/sql/util.c                                 | 17 ++++++---
 .../gh-4766-wrong-cast-from-blob-to-int.test.lua   | 42 +++++++++++++++++++++-
 2 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/src/box/sql/util.c b/src/box/sql/util.c
index f908e9c..c556b98 100644
--- a/src/box/sql/util.c
+++ b/src/box/sql/util.c
@@ -467,14 +467,21 @@ sql_atoi64(const char *z, int64_t *val, bool *is_neg, int length)
 	if (*z == '-')
 		*is_neg = true;
 
+	/*
+	 * BLOB data may not end with '\0'. Because of this, the
+	 * strtoll() and strtoull() functions may return an
+	 * incorrect result. To fix this, let's copy the value for
+	 * decoding into static memory and add '\0' to it.
+	 */
+	if (length > SMALL_STATIC_SIZE - 1)
+		return -1;
+	const char *str_value = tt_cstr(z, length);
 	char *end = NULL;
 	errno = 0;
-	if (*z == '-') {
-		*is_neg = true;
-		*val = strtoll(z, &end, 10);
+	if (*is_neg) {
+		*val = strtoll(str_value, &end, 10);
 	} else {
-		*is_neg = false;
-		uint64_t u_val = strtoull(z, &end, 10);
+		uint64_t u_val = strtoull(str_value, &end, 10);
 		*val = u_val;
 	}
 	/* Overflow and underflow errors. */
diff --git a/test/sql-tap/gh-4766-wrong-cast-from-blob-to-int.test.lua b/test/sql-tap/gh-4766-wrong-cast-from-blob-to-int.test.lua
index 559e33d..37aae87 100755
--- a/test/sql-tap/gh-4766-wrong-cast-from-blob-to-int.test.lua
+++ b/test/sql-tap/gh-4766-wrong-cast-from-blob-to-int.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(12)
+test:plan(15)
 
 --
 -- Make sure that STRING or BLOB that contains DOUBLE value cannot
@@ -107,4 +107,44 @@ test:do_catchsql_test(
         1, "Type mismatch: can not convert varbinary to integer"
     })
 
+--
+-- Make sure that a blob as part of a tuple can be cast to NUMBER,
+-- INTEGER and UNSIGNED. Prior to this patch, an error could
+-- appear due to the absence of '\0' at the end of the BLOB.
+--
+test:do_execsql_test(
+    "gh-4766-13",
+    [[
+        CREATE TABLE t1 (a VARBINARY PRIMARY KEY);
+        INSERT INTO t1 VALUES (X'33'), (X'372020202020');
+        SELECT a, CAST(a AS NUMBER), CAST(a AS INTEGER), CAST(a AS UNSIGNED) FROM t1;
+    ]], {
+        '3', 3, 3, 3, '7     ', 7, 7, 7
+    })
+
+--
+-- Make sure that BLOB longer than 12287 bytes cannot be cast to
+-- INTEGER.
+--
+long_str = string.rep('0', 12284)
+test:do_execsql_test(
+    "gh-4766-14",
+    "SELECT CAST('" .. long_str .. "123'" .. " AS INTEGER);", {
+        123
+    })
+
+
+test:do_catchsql_test(
+    "gh-4766-15",
+    "SELECT CAST('" .. long_str .. "1234'" .. " AS INTEGER);", {
+        1, "Type mismatch: can not convert 000000000000000000000000000000000" ..
+        "0000000000000000000000000000000000000000000000000000000000000000000" ..
+        "0000000000000000000000000000000000000000000000000000000000000000000" ..
+        "0000000000000000000000000000000000000000000000000000000000000000000" ..
+        "0000000000000000000000000000000000000000000000000000000000000000000" ..
+        "0000000000000000000000000000000000000000000000000000000000000000000" ..
+        "0000000000000000000000000000000000000000000000000000000000000000000" ..
+        "000000000000000000000000000000000000000000000"
+    })
+
 test:finish_test()
-- 
2.7.4

  parent reply	other threads:[~2020-03-27 11:33 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-27 11:33 [Tarantool-patches] [PATCH v4 0/3] sql: fix CAST() from BLOB " imeevma
2020-03-27 11:33 ` [Tarantool-patches] [PATCH v4 1/3] sql: fix CAST() from STRING " imeevma
2020-03-27 16:46   ` Nikita Pettik
2020-04-10 10:39     ` Mergen Imeev
2020-04-10 10:43       ` Mergen Imeev
2020-04-10 13:05         ` Nikita Pettik
2020-04-10 17:06           ` Imeev Mergen
2020-04-15 11:13             ` Nikita Pettik
2020-04-10 12:46       ` Nikita Pettik
2020-04-10 13:05         ` Imeev Mergen
2020-03-27 11:33 ` [Tarantool-patches] [PATCH v4 2/3] sql: fix implicit cast " imeevma
2020-03-27 16:54   ` Nikita Pettik
2020-04-10 10:41     ` Mergen Imeev
2020-04-10 12:57       ` Nikita Pettik
2020-04-10 18:09         ` Mergen Imeev
2020-03-27 11:33 ` imeevma [this message]
2020-03-27 16:54   ` [Tarantool-patches] [PATCH v4 3/3] sql: add '\0' to the BLOB when it is cast " Nikita Pettik
2020-04-16  0:03 ` [Tarantool-patches] [PATCH v4 0/3] sql: fix CAST() from BLOB " Nikita Pettik

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=3068e777d61da1f73764c68bc94074fe01119af9.1585308644.git.imeevma@gmail.com \
    --to=imeevma@tarantool.org \
    --cc=korablev@tarantool.org \
    --cc=tarantool-patches@dev.tarantool.org \
    --cc=tsafin@tarantool.org \
    --subject='Re: [Tarantool-patches] [PATCH v4 3/3] sql: add '\''\0'\'' to the BLOB when it is cast 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