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
next prev 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