[Tarantool-patches] [PATCH v2 1/4] sql: truncate values in type mismatch error

imeevma at tarantool.org imeevma at tarantool.org
Mon Jul 5 18:27:50 MSK 2021


STRING, MAP, and ARRAY values that are too long can make the type
mismatch error description less descriptive than necessary. This patch
truncates values that are too long and adds "..." to indicate that the
value has been truncated.

Part of #6176
---
 src/box/sql/mem.c                             | 22 ++++++---
 src/box/sql/mem.h                             |  3 +-
 ...-4766-wrong-cast-from-blob-to-int.test.lua |  7 +--
 test/sql-tap/sql-errors.test.lua              | 47 ++++++++++++++++++-
 test/sql/types.result                         |  6 +--
 5 files changed, 66 insertions(+), 19 deletions(-)

diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c
index 6f3bf52e5..630f1a135 100644
--- a/src/box/sql/mem.c
+++ b/src/box/sql/mem.c
@@ -56,6 +56,7 @@ sqlVdbeMemGrow(struct Mem *pMem, int n, int preserve);
 
 enum {
 	BUF_SIZE = 32,
+	STR_VALUE_MAX_LEN = 128,
 };
 
 bool
@@ -71,26 +72,35 @@ mem_is_field_compatible(const struct Mem *mem, enum field_type type)
 const char *
 mem_str(const struct Mem *mem)
 {
-	char buf[BUF_SIZE];
+	char buf[STR_VALUE_MAX_LEN + 1];
 	switch (mem->type) {
 	case MEM_TYPE_NULL:
 		return "NULL";
 	case MEM_TYPE_STR:
-		if ((mem->flags & MEM_Term) != 0)
-			return mem->z;
+		if (mem->n > STR_VALUE_MAX_LEN) {
+			memcpy(buf, mem->z, STR_VALUE_MAX_LEN);
+			buf[STR_VALUE_MAX_LEN] = '\0';
+			return tt_sprintf("%s...", buf);
+		}
 		return tt_cstr(mem->z, mem->n);
 	case MEM_TYPE_INT:
 		return tt_sprintf("%lld", mem->u.i);
 	case MEM_TYPE_UINT:
 		return tt_sprintf("%llu", mem->u.u);
 	case MEM_TYPE_DOUBLE:
-		sql_snprintf(BUF_SIZE, &buf[0], "%!.15g", mem->u.r);
+		sql_snprintf(STR_VALUE_MAX_LEN + 1, buf, "%!.15g", mem->u.r);
 		return tt_sprintf("%s", buf);
 	case MEM_TYPE_BIN:
 		return "varbinary";
 	case MEM_TYPE_MAP:
-	case MEM_TYPE_ARRAY:
-		return mp_str(mem->z);
+	case MEM_TYPE_ARRAY: {
+		const char *str = mp_str(mem->z);
+		if (strlen(str) <= STR_VALUE_MAX_LEN)
+			return str;
+		memcpy(buf, str, STR_VALUE_MAX_LEN);
+		buf[STR_VALUE_MAX_LEN] = '\0';
+		return tt_sprintf("%s...", buf);
+	}
 	case MEM_TYPE_UUID:
 		return tt_uuid_str(&mem->u.uuid);
 	case MEM_TYPE_BOOL:
diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h
index b3cd5c545..0bbc63e68 100644
--- a/src/box/sql/mem.h
+++ b/src/box/sql/mem.h
@@ -264,7 +264,8 @@ mem_is_field_compatible(const struct Mem *mem, enum field_type type);
 
 /**
  * Return a string that represent content of MEM. String is either allocated
- * using static_alloc() of just a static variable.
+ * using static_alloc() of just a static variable. This function should only be
+ * used for debugging or displaying MEM values in errors.
  */
 const char *
 mem_str(const struct Mem *mem);
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 da8c2dcd6..28cf50184 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
@@ -34,12 +34,7 @@ test:do_catchsql_test(
     "SELECT CAST('" .. long_str .. "1234'" .. " AS INTEGER);", {
         1, "Type mismatch: can not convert 000000000000000000000000000000000" ..
         "0000000000000000000000000000000000000000000000000000000000000000000" ..
-        "0000000000000000000000000000000000000000000000000000000000000000000" ..
-        "0000000000000000000000000000000000000000000000000000000000000000000" ..
-        "0000000000000000000000000000000000000000000000000000000000000000000" ..
-        "0000000000000000000000000000000000000000000000000000000000000000000" ..
-        "0000000000000000000000000000000000000000000000000000000000000000000" ..
-        "000000000000000000000000000000000000000000000"
+        "0000000000000000000000000000... to integer"
     })
 
 test:finish_test()
diff --git a/test/sql-tap/sql-errors.test.lua b/test/sql-tap/sql-errors.test.lua
index 469193a2b..96ee683eb 100755
--- a/test/sql-tap/sql-errors.test.lua
+++ b/test/sql-tap/sql-errors.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 local test = require("sqltester")
-test:plan(72)
+test:plan(76)
 
 test:execsql([[
 	CREATE TABLE t0 (i INT PRIMARY KEY, a INT);
@@ -780,4 +780,49 @@ test:do_catchsql_test(
 		-- </sql-errors-2.9>
 	})
 
+--
+-- gh-6176: Make sure that type mismatch error description with too long STRING,
+-- MAP or ARRAY is printed correctly.
+--
+local str1 = string.rep('a', 200)
+local str2 = string.rep('ы', 200)
+
+test:do_catchsql_test(
+	"sql-errors-3.1",
+	"SELECT CAST('"..str1.."'AS UNSIGNED);", {
+		1, "Type mismatch: can not convert aaaaaaaaaaaaaaaaaaaaaaaaaa"..
+		"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..
+		"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa... to unsigned"
+	})
+
+test:do_catchsql_test(
+	"sql-errors-3.2",
+	"SELECT CAST('"..str2.."'AS UNSIGNED);", {
+		1, "Type mismatch: can not convert ыыыыыыыыыыыыыыыыыыыыыыыыыы"..
+		"ыыыыыыыыыыыыыыыыыыыыыыыыыыыыыыыыыыыыыы... to unsigned"
+	})
+
+local format = {{'I', 'integer'}, {'A', 'array'}, {'M', 'map'}}
+local s = box.schema.space.create('TEST', {format=format})
+s:create_index('I')
+s:insert({1, {str1}, {a = 1, b = str1}})
+
+test:do_catchsql_test(
+	"sql-errors-3.3",
+	"SELECT CAST(a AS UNSIGNED) from test;", {
+		1, 'Type mismatch: can not convert ["aaaaaaaaaaaaaaaaaaaaaaaa'..
+		'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'..
+		'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa... to unsigned'
+	})
+
+test:do_catchsql_test(
+	"sql-errors-3.4",
+	"SELECT CAST(m AS UNSIGNED) from test;", {
+		1, 'Type mismatch: can not convert {"a": 1, "b": "aaaaaaaaaaa'..
+		'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'..
+		'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa... to unsigned'
+	})
+
+test:execsql('DROP TABLE test;')
+
 test:finish_test()
diff --git a/test/sql/types.result b/test/sql/types.result
index 687ca3b15..a46967158 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -1651,11 +1651,7 @@ box.execute('INSERT INTO t1(a) SELECT a FROM t2;')
 - null
 - 'Type mismatch: can not convert [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
   15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
-  35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
-  55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
-  75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
-  95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
-  112, 113, 114, 115, 116, 117, 11'
+  ... to scalar'
 ...
 s:drop()
 ---
-- 
2.25.1



More information about the Tarantool-patches mailing list